[{"data":1,"prerenderedAt":5060},["ShallowReactive",2],{"authors":3,"article-2022-07-21-lets-build-a-di-system-in-javascript-using-meta-programming":331},[4,23,35,48,61,73,85,98,111,124,136,148,161,173,185,197,209,221,233,245,258,270,282,295,307,319],{"id":5,"title":6,"body":7,"description":11,"extension":14,"meta":15,"name":16,"navigation":17,"path":18,"readingTime":19,"seo":20,"stem":21,"__hash__":22},"authors\u002Fauthors\u002Falexandre-guillon.md","Software Engineer",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"md",{},"Alexandre Guillon",true,"\u002Fauthors\u002Falexandre-guillon",1,{"title":6,"description":11},"authors\u002Falexandre-guillon","4tf48mjyjFNqItOHaulICbrjeCyMag1o6801uHeTz98",{"id":24,"title":6,"body":25,"description":11,"extension":14,"meta":29,"name":30,"navigation":17,"path":31,"readingTime":19,"seo":32,"stem":33,"__hash__":34},"authors\u002Fauthors\u002Falexis-ablain.md",{"type":8,"value":26,"toc":27},[],{"title":11,"searchDepth":12,"depth":12,"links":28},[],{},"Alexis Ablain","\u002Fauthors\u002Falexis-ablain",{"title":6,"description":11},"authors\u002Falexis-ablain","_SIAtB7f-39e5t3GiJof81NP47s6MGo2n4gaHkTy1uQ",{"id":36,"title":37,"body":38,"description":11,"extension":14,"meta":42,"name":43,"navigation":17,"path":44,"readingTime":19,"seo":45,"stem":46,"__hash__":47},"authors\u002Fauthors\u002Faxel-shaita.md","Engineering Manager",{"type":8,"value":39,"toc":40},[],{"title":11,"searchDepth":12,"depth":12,"links":41},[],{},"Axel Shaïta","\u002Fauthors\u002Faxel-shaita",{"title":37,"description":11},"authors\u002Faxel-shaita","fK0argUhsBkWLjpTAhY13oYLVzQthcEYkCEdtHWmIgE",{"id":49,"title":50,"body":51,"description":11,"extension":14,"meta":55,"name":56,"navigation":17,"path":57,"readingTime":19,"seo":58,"stem":59,"__hash__":60},"authors\u002Fauthors\u002Fbaptiste-faure.md","Head of Talent Acquisition",{"type":8,"value":52,"toc":53},[],{"title":11,"searchDepth":12,"depth":12,"links":54},[],{},"Baptiste Faure","\u002Fauthors\u002Fbaptiste-faure",{"title":50,"description":11},"authors\u002Fbaptiste-faure","ELisToYtcgHmgdVWZkCclTPV6exZtfyXqhpx1jjbJHs",{"id":62,"title":6,"body":63,"description":11,"extension":14,"meta":67,"name":68,"navigation":17,"path":69,"readingTime":19,"seo":70,"stem":71,"__hash__":72},"authors\u002Fauthors\u002Fbenjamin-bouillot.md",{"type":8,"value":64,"toc":65},[],{"title":11,"searchDepth":12,"depth":12,"links":66},[],{},"Benjamin Bouillot","\u002Fauthors\u002Fbenjamin-bouillot",{"title":6,"description":11},"authors\u002Fbenjamin-bouillot","tbhCFZyfTt7ZM5b5YgqQ2nhgnSTl8BweaQQryc87fHo",{"id":74,"title":37,"body":75,"description":11,"extension":14,"meta":79,"name":80,"navigation":17,"path":81,"readingTime":19,"seo":82,"stem":83,"__hash__":84},"authors\u002Fauthors\u002Fcedric-nicoloso.md",{"type":8,"value":76,"toc":77},[],{"title":11,"searchDepth":12,"depth":12,"links":78},[],{},"Cédric Nicoloso","\u002Fauthors\u002Fcedric-nicoloso",{"title":37,"description":11},"authors\u002Fcedric-nicoloso","ibSoh4VZYiWYTuLOnZTedaAfcnvet1Q9H7ogW0LgorY",{"id":86,"title":87,"body":88,"description":11,"extension":14,"meta":92,"name":93,"navigation":17,"path":94,"readingTime":19,"seo":95,"stem":96,"__hash__":97},"authors\u002Fauthors\u002Fdavid-touzet.md","Staff Engineer",{"type":8,"value":89,"toc":90},[],{"title":11,"searchDepth":12,"depth":12,"links":91},[],{},"David Touzet","\u002Fauthors\u002Fdavid-touzet",{"title":87,"description":11},"authors\u002Fdavid-touzet","dHWwnQxb1Ubt-WwXWEODGEo9AFoq1cJUhfg3kdnYSBM",{"id":99,"title":100,"body":101,"description":11,"extension":14,"meta":105,"name":106,"navigation":17,"path":107,"readingTime":19,"seo":108,"stem":109,"__hash__":110},"authors\u002Fauthors\u002Feloise-chizat.md","Data Engineer",{"type":8,"value":102,"toc":103},[],{"title":11,"searchDepth":12,"depth":12,"links":104},[],{},"Eloïse Chizat","\u002Fauthors\u002Feloise-chizat",{"title":100,"description":11},"authors\u002Feloise-chizat","Utd72Vm9qT4hh2ZbFi6a2_nXw5Wb494Ed_HL1ra5yw8",{"id":112,"title":113,"body":114,"description":11,"extension":14,"meta":118,"name":119,"navigation":17,"path":120,"readingTime":19,"seo":121,"stem":122,"__hash__":123},"authors\u002Fauthors\u002Femmanuel-auclair.md","Staff engineer",{"type":8,"value":115,"toc":116},[],{"title":11,"searchDepth":12,"depth":12,"links":117},[],{},"Emmanuel Auclair","\u002Fauthors\u002Femmanuel-auclair",{"title":113,"description":11},"authors\u002Femmanuel-auclair","MtsA8THNLEn0dTtYEIQaGwDuf7MjQL55IOeei5gugEg",{"id":125,"title":6,"body":126,"description":11,"extension":14,"meta":130,"name":131,"navigation":17,"path":132,"readingTime":19,"seo":133,"stem":134,"__hash__":135},"authors\u002Fauthors\u002Fhoreb-parraud.md",{"type":8,"value":127,"toc":128},[],{"title":11,"searchDepth":12,"depth":12,"links":129},[],{},"Horeb Parraud","\u002Fauthors\u002Fhoreb-parraud",{"title":6,"description":11},"authors\u002Fhoreb-parraud","ajjsnUX4ohZI-ghMdbb92q_taWDkKXVZSLZXoAeLQtg",{"id":137,"title":37,"body":138,"description":11,"extension":14,"meta":142,"name":143,"navigation":17,"path":144,"readingTime":19,"seo":145,"stem":146,"__hash__":147},"authors\u002Fauthors\u002Fhugo-contreras.md",{"type":8,"value":139,"toc":140},[],{"title":11,"searchDepth":12,"depth":12,"links":141},[],{},"Hugo Contreras","\u002Fauthors\u002Fhugo-contreras",{"title":37,"description":11},"authors\u002Fhugo-contreras","2nc3VMu9ASq9Z6Pwx2-7-Ye991Pww4p-UEDBQFfjF-Q",{"id":149,"title":150,"body":151,"description":11,"extension":14,"meta":155,"name":156,"navigation":17,"path":157,"readingTime":19,"seo":158,"stem":159,"__hash__":160},"authors\u002Fauthors\u002Fjulien-tassin.md","Head of Engineering",{"type":8,"value":152,"toc":153},[],{"title":11,"searchDepth":12,"depth":12,"links":154},[],{},"Julien Tassin","\u002Fauthors\u002Fjulien-tassin",{"title":150,"description":11},"authors\u002Fjulien-tassin","iUIHI7SITje38Jh9X9uvYs4-VsHx4eCdt6hAlyLFG_o",{"id":162,"title":6,"body":163,"description":11,"extension":14,"meta":167,"name":168,"navigation":17,"path":169,"readingTime":19,"seo":170,"stem":171,"__hash__":172},"authors\u002Fauthors\u002Flaurent-renard.md",{"type":8,"value":164,"toc":165},[],{"title":11,"searchDepth":12,"depth":12,"links":166},[],{},"Laurent Renard","\u002Fauthors\u002Flaurent-renard",{"title":6,"description":11},"authors\u002Flaurent-renard","5BP7Ed-pt1SQHjh0UJ1XUrlLTcdlFaDoKBCP4deHq8A",{"id":174,"title":6,"body":175,"description":11,"extension":14,"meta":179,"name":180,"navigation":17,"path":181,"readingTime":19,"seo":182,"stem":183,"__hash__":184},"authors\u002Fauthors\u002Fleo-martin.md",{"type":8,"value":176,"toc":177},[],{"title":11,"searchDepth":12,"depth":12,"links":178},[],{},"Léo Martin","\u002Fauthors\u002Fleo-martin",{"title":6,"description":11},"authors\u002Fleo-martin","eYxCHkRgbGDV7shKdTA9s7Tu0zGV4yDGFoKR5MHQntY",{"id":186,"title":6,"body":187,"description":11,"extension":14,"meta":191,"name":192,"navigation":17,"path":193,"readingTime":19,"seo":194,"stem":195,"__hash__":196},"authors\u002Fauthors\u002Floic-bousquet.md",{"type":8,"value":188,"toc":189},[],{"title":11,"searchDepth":12,"depth":12,"links":190},[],{},"Loïc Bousquet","\u002Fauthors\u002Floic-bousquet",{"title":6,"description":11},"authors\u002Floic-bousquet","ko12qZwiGL8XNjAoy9oWypPkIjr29Pbq7vhdtgldqeQ",{"id":198,"title":6,"body":199,"description":11,"extension":14,"meta":203,"name":204,"navigation":17,"path":205,"readingTime":19,"seo":206,"stem":207,"__hash__":208},"authors\u002Fauthors\u002Floic-poullain.md",{"type":8,"value":200,"toc":201},[],{"title":11,"searchDepth":12,"depth":12,"links":202},[],{},"Loïc Poullain","\u002Fauthors\u002Floic-poullain",{"title":6,"description":11},"authors\u002Floic-poullain","oRIyJhFRTqxy5dLCYQ2OnYZ1DB-gLDUM-85vTSYuTF0",{"id":210,"title":100,"body":211,"description":11,"extension":14,"meta":215,"name":216,"navigation":17,"path":217,"readingTime":19,"seo":218,"stem":219,"__hash__":220},"authors\u002Fauthors\u002Fmaud-lelu.md",{"type":8,"value":212,"toc":213},[],{"title":11,"searchDepth":12,"depth":12,"links":214},[],{},"Maud Lélu","\u002Fauthors\u002Fmaud-lelu",{"title":100,"description":11},"authors\u002Fmaud-lelu","MMbsCKuE41OMHusrl12FIEsI-Trx7l8Nn_ANhvj2_y4",{"id":222,"title":37,"body":223,"description":11,"extension":14,"meta":227,"name":228,"navigation":17,"path":229,"readingTime":19,"seo":230,"stem":231,"__hash__":232},"authors\u002Fauthors\u002Fnicolas-poirier.md",{"type":8,"value":224,"toc":225},[],{"title":11,"searchDepth":12,"depth":12,"links":226},[],{},"Nicolas Poirier","\u002Fauthors\u002Fnicolas-poirier",{"title":37,"description":11},"authors\u002Fnicolas-poirier","dXrJkYo8az4SN_D23aYc3fQ7z8s1dR2a0lt1ogjAjJs",{"id":234,"title":37,"body":235,"description":11,"extension":14,"meta":239,"name":240,"navigation":17,"path":241,"readingTime":19,"seo":242,"stem":243,"__hash__":244},"authors\u002Fauthors\u002Fraphael-sauget.md",{"type":8,"value":236,"toc":237},[],{"title":11,"searchDepth":12,"depth":12,"links":238},[],{},"Raphaël Sauget","\u002Fauthors\u002Fraphael-sauget",{"title":37,"description":11},"authors\u002Fraphael-sauget","Uri9bcq0QDuxRA0PbBoNtu7p_5L3dALu4kzcXVW0xyM",{"id":246,"title":247,"body":248,"description":11,"extension":14,"meta":252,"name":253,"navigation":17,"path":254,"readingTime":19,"seo":255,"stem":256,"__hash__":257},"authors\u002Fauthors\u002Fromain-koenig.md","Co-funder & Head of innovation",{"type":8,"value":249,"toc":250},[],{"title":11,"searchDepth":12,"depth":12,"links":251},[],{},"Romain Koenig","\u002Fauthors\u002Fromain-koenig",{"title":247,"description":11},"authors\u002Fromain-koenig","uyS8--eG2_ezyqRABcJnMJmQKKuSArhPWd14aUvFeEw",{"id":259,"title":37,"body":260,"description":11,"extension":14,"meta":264,"name":265,"navigation":17,"path":266,"readingTime":19,"seo":267,"stem":268,"__hash__":269},"authors\u002Fauthors\u002Fromaric-juniet.md",{"type":8,"value":261,"toc":262},[],{"title":11,"searchDepth":12,"depth":12,"links":263},[],{},"Romaric Juniet","\u002Fauthors\u002Fromaric-juniet",{"title":37,"description":11},"authors\u002Fromaric-juniet","4Zb2artgT-eo-PHLXi3xi4d5t7s6PfhUxeSfXIikSUY",{"id":271,"title":6,"body":272,"description":11,"extension":14,"meta":276,"name":277,"navigation":17,"path":278,"readingTime":19,"seo":279,"stem":280,"__hash__":281},"authors\u002Fauthors\u002Fstanyslas-bres.md",{"type":8,"value":273,"toc":274},[],{"title":11,"searchDepth":12,"depth":12,"links":275},[],{},"Stanyslas Bres","\u002Fauthors\u002Fstanyslas-bres",{"title":6,"description":11},"authors\u002Fstanyslas-bres","Xa0SahETuiN4q1jrmR2ych3moAqcZ2LbU7vSfEt2RuU",{"id":283,"title":284,"body":285,"description":11,"extension":14,"meta":289,"name":290,"navigation":17,"path":291,"readingTime":19,"seo":292,"stem":293,"__hash__":294},"authors\u002Fauthors\u002Ftalent-acquisition.md","Talent Acquisition",{"type":8,"value":286,"toc":287},[],{"title":11,"searchDepth":12,"depth":12,"links":288},[],{},"Équipe Talent Acquisition","\u002Fauthors\u002Ftalent-acquisition",{"description":11},"authors\u002Ftalent-acquisition","doDfE76txftQ4wIiKjJoDmSpyzSKk0tzlgVAp6-opAY",{"id":296,"title":6,"body":297,"description":11,"extension":14,"meta":301,"name":302,"navigation":17,"path":303,"readingTime":19,"seo":304,"stem":305,"__hash__":306},"authors\u002Fauthors\u002Fvictor-borg.md",{"type":8,"value":298,"toc":299},[],{"title":11,"searchDepth":12,"depth":12,"links":300},[],{},"Victor Borg","\u002Fauthors\u002Fvictor-borg",{"title":6,"description":11},"authors\u002Fvictor-borg","-Za-JweoiP6hyclue_WkxMXdRUDTczPGlJf6AZckjUc",{"id":308,"title":6,"body":309,"description":11,"extension":14,"meta":313,"name":314,"navigation":17,"path":315,"readingTime":19,"seo":316,"stem":317,"__hash__":318},"authors\u002Fauthors\u002Fvirgil-roger.md",{"type":8,"value":310,"toc":311},[],{"title":11,"searchDepth":12,"depth":12,"links":312},[],{},"Virgil Roger","\u002Fauthors\u002Fvirgil-roger",{"title":6,"description":11},"authors\u002Fvirgil-roger","DfVFe5j0bCgXeEr381ZYOM5DP4m-pWb93J9-m_muKJ0",{"id":320,"title":6,"body":321,"description":11,"extension":14,"meta":325,"name":326,"navigation":17,"path":327,"readingTime":19,"seo":328,"stem":329,"__hash__":330},"authors\u002Fauthors\u002Fyukan-zhao.md",{"type":8,"value":322,"toc":323},[],{"title":11,"searchDepth":12,"depth":12,"links":324},[],{},"Yukan Zhao","\u002Fauthors\u002Fyukan-zhao",{"title":6,"description":11},"authors\u002Fyukan-zhao","LRPHugtAJnWHsmHxy9_SR5Zas_C5p-GR_uHEs1Fhk_E",{"id":332,"title":333,"author":334,"body":335,"date":5050,"description":5051,"extension":14,"lang":5052,"meta":5053,"navigation":17,"path":5054,"published":17,"readingTime":628,"seo":5055,"stem":5056,"tags":5057,"__hash__":5059},"articles\u002Farticles\u002F2022-07-21-lets-build-a-di-system-in-javascript-using-meta-programming.md","Let’s build a DI system in Javascript using meta programming","laurent-renard",{"type":8,"value":336,"toc":5040},[337,341,344,349,352,644,647,660,663,784,787,815,819,822,911,931,935,942,968,971,976,1225,1230,1290,1295,1434,1437,1440,1444,1447,1458,1466,1469,1606,1609,1801,1814,1817,1825,2163,2166,2179,2357,2361,2370,2373,2376,2620,2623,2634,2637,3010,3014,3021,3024,3027,3042,3061,3064,3343,3346,3406,3416,3510,3513,3620,3623,3817,3826,3848,4476,4480,4483,4556,4559,4891,4897,4900,5023,5027,5036],[338,339,340],"p",{},"Dependency Injection (DI) is a technique in which a software component receives other components\n(its dependencies) without it to have the responsibility to resolve and instantiate them.",[338,342,343],{},"This can favour loose coupling between the components, and separation of concerns: the client has\nonly to manage its own functionalities.",[345,346,348],"h2",{"id":347},"introduction-example","Introduction example",[338,350,351],{},"Consider the following pseudo code:",[353,354,358],"pre",{"className":355,"code":356,"language":357,"meta":11,"style":11},"language-ts shiki shiki-themes github-light github-dark","\u002F\u002F bankAccount.service.js\nimport { createConnectionPool } from \".\u002Fdb.js\";\nimport { createUsersService } from \".\u002Fuser.js\";\nimport { createAuthorizationService } from \".\u002Fauthorization.js\";\n\nexport const createBankAccountService = ({ conf }) => {\n  const db = createConnectionPool({ conf });\n  const Users = createUsersService({ db });\n  const Authorization = createAuthorizationService({ Users });\n\n  return {\n    async createBankAccount({ userId, bankAccount }) {\n      const authorization = Authorization.authorizeBankAccount({ userId });\n      if (!authorization) {\n        throw new Error(\"can not authorize bank account\");\n      }\n      return db.query(createBankAccountQuery({ bankAccount }));\n    },\n  };\n};\n","ts",[359,360,361,369,389,404,419,425,457,475,491,507,512,520,544,564,579,600,606,626,632,638],"code",{"__ignoreMap":11},[362,363,365],"span",{"class":364,"line":19},"line",[362,366,368],{"class":367},"sJ8bj","\u002F\u002F bankAccount.service.js\n",[362,370,371,375,379,382,386],{"class":364,"line":12},[362,372,374],{"class":373},"szBVR","import",[362,376,378],{"class":377},"sVt8B"," { createConnectionPool } ",[362,380,381],{"class":373},"from",[362,383,385],{"class":384},"sZZnC"," \".\u002Fdb.js\"",[362,387,388],{"class":377},";\n",[362,390,392,394,397,399,402],{"class":364,"line":391},3,[362,393,374],{"class":373},[362,395,396],{"class":377}," { createUsersService } ",[362,398,381],{"class":373},[362,400,401],{"class":384}," \".\u002Fuser.js\"",[362,403,388],{"class":377},[362,405,407,409,412,414,417],{"class":364,"line":406},4,[362,408,374],{"class":373},[362,410,411],{"class":377}," { createAuthorizationService } ",[362,413,381],{"class":373},[362,415,416],{"class":384}," \".\u002Fauthorization.js\"",[362,418,388],{"class":377},[362,420,422],{"class":364,"line":421},5,[362,423,424],{"emptyLinePlaceholder":17},"\n",[362,426,428,431,434,438,441,444,448,451,454],{"class":364,"line":427},6,[362,429,430],{"class":373},"export",[362,432,433],{"class":373}," const",[362,435,437],{"class":436},"sScJk"," createBankAccountService",[362,439,440],{"class":373}," =",[362,442,443],{"class":377}," ({ ",[362,445,447],{"class":446},"s4XuR","conf",[362,449,450],{"class":377}," }) ",[362,452,453],{"class":373},"=>",[362,455,456],{"class":377}," {\n",[362,458,460,463,467,469,472],{"class":364,"line":459},7,[362,461,462],{"class":373},"  const",[362,464,466],{"class":465},"sj4cs"," db",[362,468,440],{"class":373},[362,470,471],{"class":436}," createConnectionPool",[362,473,474],{"class":377},"({ conf });\n",[362,476,478,480,483,485,488],{"class":364,"line":477},8,[362,479,462],{"class":373},[362,481,482],{"class":465}," Users",[362,484,440],{"class":373},[362,486,487],{"class":436}," createUsersService",[362,489,490],{"class":377},"({ db });\n",[362,492,494,496,499,501,504],{"class":364,"line":493},9,[362,495,462],{"class":373},[362,497,498],{"class":465}," Authorization",[362,500,440],{"class":373},[362,502,503],{"class":436}," createAuthorizationService",[362,505,506],{"class":377},"({ Users });\n",[362,508,510],{"class":364,"line":509},10,[362,511,424],{"emptyLinePlaceholder":17},[362,513,515,518],{"class":364,"line":514},11,[362,516,517],{"class":373},"  return",[362,519,456],{"class":377},[362,521,523,526,529,532,535,538,541],{"class":364,"line":522},12,[362,524,525],{"class":373},"    async",[362,527,528],{"class":436}," createBankAccount",[362,530,531],{"class":377},"({ ",[362,533,534],{"class":446},"userId",[362,536,537],{"class":377},", ",[362,539,540],{"class":446},"bankAccount",[362,542,543],{"class":377}," }) {\n",[362,545,547,550,553,555,558,561],{"class":364,"line":546},13,[362,548,549],{"class":373},"      const",[362,551,552],{"class":465}," authorization",[362,554,440],{"class":373},[362,556,557],{"class":377}," Authorization.",[362,559,560],{"class":436},"authorizeBankAccount",[362,562,563],{"class":377},"({ userId });\n",[362,565,567,570,573,576],{"class":364,"line":566},14,[362,568,569],{"class":373},"      if",[362,571,572],{"class":377}," (",[362,574,575],{"class":373},"!",[362,577,578],{"class":377},"authorization) {\n",[362,580,582,585,588,591,594,597],{"class":364,"line":581},15,[362,583,584],{"class":373},"        throw",[362,586,587],{"class":373}," new",[362,589,590],{"class":436}," Error",[362,592,593],{"class":377},"(",[362,595,596],{"class":384},"\"can not authorize bank account\"",[362,598,599],{"class":377},");\n",[362,601,603],{"class":364,"line":602},16,[362,604,605],{"class":377},"      }\n",[362,607,609,612,615,618,620,623],{"class":364,"line":608},17,[362,610,611],{"class":373},"      return",[362,613,614],{"class":377}," db.",[362,616,617],{"class":436},"query",[362,619,593],{"class":377},[362,621,622],{"class":436},"createBankAccountQuery",[362,624,625],{"class":377},"({ bankAccount }));\n",[362,627,629],{"class":364,"line":628},18,[362,630,631],{"class":377},"    },\n",[362,633,635],{"class":364,"line":634},19,[362,636,637],{"class":377},"  };\n",[362,639,641],{"class":364,"line":640},20,[362,642,643],{"class":377},"};\n",[338,645,646],{},"You’ll note that the bank account service:",[648,649,650,654,657],"ul",{},[651,652,653],"li",{},"Has to create its dependencies, which may imply creating transitive dependencies: ie the\ndependencies of its own dependencies. In particular, the bank account service creates a user\nservice it will not use by itself.",[651,655,656],{},"Has to import the factories of its dependencies (the functions used to create those services). It\nmeans the bank account service needs to know where to find these factories. As a side effect, the\nbank account service is coupled to specific implementations of its dependencies rather than using\nabstract interfaces.",[651,658,659],{},"Although not a big problem, this instanciation code also clutters the service logic.",[338,661,662],{},"In comparison, consider the following snippet:",[353,664,666],{"className":355,"code":665,"language":357,"meta":11,"style":11},"export const createBankAccountService = ({ Authorization, db }) => {\n  return {\n    async createBankAccount({ userId, bankAccount }) {\n      const authorization = Authorization.authorizeBankAccount({ userId });\n      if (!authorization) {\n        throw new Error(\"can not authorize bank account\");\n      }\n      return db.query(createBankAccountQuery({ bankAccount }));\n    },\n  };\n};\n",[359,667,668,694,700,716,730,740,754,758,772,776,780],{"__ignoreMap":11},[362,669,670,672,674,676,678,680,683,685,688,690,692],{"class":364,"line":19},[362,671,430],{"class":373},[362,673,433],{"class":373},[362,675,437],{"class":436},[362,677,440],{"class":373},[362,679,443],{"class":377},[362,681,682],{"class":446},"Authorization",[362,684,537],{"class":377},[362,686,687],{"class":446},"db",[362,689,450],{"class":377},[362,691,453],{"class":373},[362,693,456],{"class":377},[362,695,696,698],{"class":364,"line":12},[362,697,517],{"class":373},[362,699,456],{"class":377},[362,701,702,704,706,708,710,712,714],{"class":364,"line":391},[362,703,525],{"class":373},[362,705,528],{"class":436},[362,707,531],{"class":377},[362,709,534],{"class":446},[362,711,537],{"class":377},[362,713,540],{"class":446},[362,715,543],{"class":377},[362,717,718,720,722,724,726,728],{"class":364,"line":406},[362,719,549],{"class":373},[362,721,552],{"class":465},[362,723,440],{"class":373},[362,725,557],{"class":377},[362,727,560],{"class":436},[362,729,563],{"class":377},[362,731,732,734,736,738],{"class":364,"line":421},[362,733,569],{"class":373},[362,735,572],{"class":377},[362,737,575],{"class":373},[362,739,578],{"class":377},[362,741,742,744,746,748,750,752],{"class":364,"line":427},[362,743,584],{"class":373},[362,745,587],{"class":373},[362,747,590],{"class":436},[362,749,593],{"class":377},[362,751,596],{"class":384},[362,753,599],{"class":377},[362,755,756],{"class":364,"line":459},[362,757,605],{"class":377},[362,759,760,762,764,766,768,770],{"class":364,"line":477},[362,761,611],{"class":373},[362,763,614],{"class":377},[362,765,617],{"class":436},[362,767,593],{"class":377},[362,769,622],{"class":436},[362,771,625],{"class":377},[362,773,774],{"class":364,"line":493},[362,775,631],{"class":377},[362,777,778],{"class":364,"line":509},[362,779,637],{"class":377},[362,781,782],{"class":364,"line":514},[362,783,643],{"class":377},[338,785,786],{},"The bank account service does not create any dependency but got them injected, with the following\ndirect benefits:",[648,788,789,796,809,812],{},[651,790,791,792,795],{},"The transitive dependency ",[359,793,794],{},"Users"," has disappeared",[651,797,798,799,801,802,804,805],{},"The service does not depend on any specific implementation of ",[359,800,682],{}," and ",[359,803,687],{}," as long as\nwhat get injected implement the same ",[806,807,808],"strong",{},"interfaces",[651,810,811],{},"The code is less cluttered and more readable",[651,813,814],{},"The service itself focuses on its own functionalities and nothing else.",[345,816,818],{"id":817},"the-injector","The Injector",[338,820,821],{},"Obviously, the code related to the resolution and instantiation of the various dependencies still\nexists somewhere, but in a component dedicated to that purpose. Let's build this component: the\ninjector.",[353,823,825],{"className":355,"code":824,"language":357,"meta":11,"style":11},"import { createConnectionPool } from \"..\u002Fdb.js\";\nimport { createUsersService } from \"..\u002Fusers.js\";\n\n\u002F\u002F etc\n\nconst injectablesManifest = {\n  db: createConnectionPool,\n  Users: createUsersService,\n};\n\nconst injectables = inject(injectablesManifest);\n",[359,826,827,840,853,857,862,866,878,883,888,892,896],{"__ignoreMap":11},[362,828,829,831,833,835,838],{"class":364,"line":19},[362,830,374],{"class":373},[362,832,378],{"class":377},[362,834,381],{"class":373},[362,836,837],{"class":384}," \"..\u002Fdb.js\"",[362,839,388],{"class":377},[362,841,842,844,846,848,851],{"class":364,"line":12},[362,843,374],{"class":373},[362,845,396],{"class":377},[362,847,381],{"class":373},[362,849,850],{"class":384}," \"..\u002Fusers.js\"",[362,852,388],{"class":377},[362,854,855],{"class":364,"line":391},[362,856,424],{"emptyLinePlaceholder":17},[362,858,859],{"class":364,"line":406},[362,860,861],{"class":367},"\u002F\u002F etc\n",[362,863,864],{"class":364,"line":421},[362,865,424],{"emptyLinePlaceholder":17},[362,867,868,871,874,876],{"class":364,"line":427},[362,869,870],{"class":373},"const",[362,872,873],{"class":465}," injectablesManifest",[362,875,440],{"class":373},[362,877,456],{"class":377},[362,879,880],{"class":364,"line":459},[362,881,882],{"class":377},"  db: createConnectionPool,\n",[362,884,885],{"class":364,"line":477},[362,886,887],{"class":377},"  Users: createUsersService,\n",[362,889,890],{"class":364,"line":493},[362,891,643],{"class":377},[362,893,894],{"class":364,"line":509},[362,895,424],{"emptyLinePlaceholder":17},[362,897,898,900,903,905,908],{"class":364,"line":514},[362,899,870],{"class":373},[362,901,902],{"class":465}," injectables",[362,904,440],{"class":373},[362,906,907],{"class":436}," inject",[362,909,910],{"class":377},"(injectablesManifest);\n",[338,912,913,914,917,918,920,921,923,924,927,928,930],{},"The ",[359,915,916],{},"inject"," function should be able to resolve the whole dependency tree based on the injectables\nmanifest specifications: if ",[359,919,794],{}," depends on ",[359,922,687],{},", then\n",[359,925,926],{},"const { Users } = inject(injectablesManifest)"," should give you an instance of ",[359,929,794],{}," with its\ndependencies resolved.",[345,932,934],{"id":933},"the-manifest","The manifest",[338,936,937,938,941],{},"The manifest (or registry) here is a sort of map whose keys are the injectables tokens (the values\nyou will use to lookup for any particular injectable), and whose values are factory functions\n(functions used to create an instance of the injectable). These factories all have the same\nsignature (Where ",[359,939,940],{},"deps"," is a map of any injectable):",[353,943,945],{"className":355,"code":944,"language":357,"meta":11,"style":11},"const factory = (deps) => injectable;\n",[359,946,947],{"__ignoreMap":11},[362,948,949,951,954,956,958,960,963,965],{"class":364,"line":19},[362,950,870],{"class":373},[362,952,953],{"class":436}," factory",[362,955,440],{"class":373},[362,957,572],{"class":377},[362,959,940],{"class":446},[362,961,962],{"class":377},") ",[362,964,453],{"class":373},[362,966,967],{"class":377}," injectable;\n",[338,969,970],{},"By using factory functions we can implement pretty much any instanciation pattern:",[648,972,973],{},[651,974,975],{},"If we always want the same instance of a given injectable (singleton), we can just wrap the\nfactory into some sort of memoize function:",[353,977,979],{"className":355,"code":978,"language":357,"meta":11,"style":11},"const factoryA = (deps) => {\n  return {\n    methodA() {},\n    methodB() {},\n  };\n};\n\nconst memoize = (fn) => {\n  let value;\n  return (deps) => {\n    if (value) {\n      return value;\n    }\n\n    return (value = fn(deps));\n  };\n};\n\nconst getMySingletonA = memoize(factoryA);\n\n\u002F\u002F which complies with\nimport { test } from \"zora\";\n\ntest(\"should always return the same instance of the injectable\", (t) => {\n  t.ok(getMySingletonA() === getMySingletonA());\n});\n",[359,980,981,1000,1006,1014,1021,1025,1029,1033,1053,1061,1075,1083,1089,1094,1098,1115,1119,1123,1127,1141,1145,1151,1166,1171,1194,1219],{"__ignoreMap":11},[362,982,983,985,988,990,992,994,996,998],{"class":364,"line":19},[362,984,870],{"class":373},[362,986,987],{"class":436}," factoryA",[362,989,440],{"class":373},[362,991,572],{"class":377},[362,993,940],{"class":446},[362,995,962],{"class":377},[362,997,453],{"class":373},[362,999,456],{"class":377},[362,1001,1002,1004],{"class":364,"line":12},[362,1003,517],{"class":373},[362,1005,456],{"class":377},[362,1007,1008,1011],{"class":364,"line":391},[362,1009,1010],{"class":436},"    methodA",[362,1012,1013],{"class":377},"() {},\n",[362,1015,1016,1019],{"class":364,"line":406},[362,1017,1018],{"class":436},"    methodB",[362,1020,1013],{"class":377},[362,1022,1023],{"class":364,"line":421},[362,1024,637],{"class":377},[362,1026,1027],{"class":364,"line":427},[362,1028,643],{"class":377},[362,1030,1031],{"class":364,"line":459},[362,1032,424],{"emptyLinePlaceholder":17},[362,1034,1035,1037,1040,1042,1044,1047,1049,1051],{"class":364,"line":477},[362,1036,870],{"class":373},[362,1038,1039],{"class":436}," memoize",[362,1041,440],{"class":373},[362,1043,572],{"class":377},[362,1045,1046],{"class":446},"fn",[362,1048,962],{"class":377},[362,1050,453],{"class":373},[362,1052,456],{"class":377},[362,1054,1055,1058],{"class":364,"line":493},[362,1056,1057],{"class":373},"  let",[362,1059,1060],{"class":377}," value;\n",[362,1062,1063,1065,1067,1069,1071,1073],{"class":364,"line":509},[362,1064,517],{"class":373},[362,1066,572],{"class":377},[362,1068,940],{"class":446},[362,1070,962],{"class":377},[362,1072,453],{"class":373},[362,1074,456],{"class":377},[362,1076,1077,1080],{"class":364,"line":514},[362,1078,1079],{"class":373},"    if",[362,1081,1082],{"class":377}," (value) {\n",[362,1084,1085,1087],{"class":364,"line":522},[362,1086,611],{"class":373},[362,1088,1060],{"class":377},[362,1090,1091],{"class":364,"line":546},[362,1092,1093],{"class":377},"    }\n",[362,1095,1096],{"class":364,"line":566},[362,1097,424],{"emptyLinePlaceholder":17},[362,1099,1100,1103,1106,1109,1112],{"class":364,"line":581},[362,1101,1102],{"class":373},"    return",[362,1104,1105],{"class":377}," (value ",[362,1107,1108],{"class":373},"=",[362,1110,1111],{"class":436}," fn",[362,1113,1114],{"class":377},"(deps));\n",[362,1116,1117],{"class":364,"line":602},[362,1118,637],{"class":377},[362,1120,1121],{"class":364,"line":608},[362,1122,643],{"class":377},[362,1124,1125],{"class":364,"line":628},[362,1126,424],{"emptyLinePlaceholder":17},[362,1128,1129,1131,1134,1136,1138],{"class":364,"line":634},[362,1130,870],{"class":373},[362,1132,1133],{"class":465}," getMySingletonA",[362,1135,440],{"class":373},[362,1137,1039],{"class":436},[362,1139,1140],{"class":377},"(factoryA);\n",[362,1142,1143],{"class":364,"line":640},[362,1144,424],{"emptyLinePlaceholder":17},[362,1146,1148],{"class":364,"line":1147},21,[362,1149,1150],{"class":367},"\u002F\u002F which complies with\n",[362,1152,1154,1156,1159,1161,1164],{"class":364,"line":1153},22,[362,1155,374],{"class":373},[362,1157,1158],{"class":377}," { test } ",[362,1160,381],{"class":373},[362,1162,1163],{"class":384}," \"zora\"",[362,1165,388],{"class":377},[362,1167,1169],{"class":364,"line":1168},23,[362,1170,424],{"emptyLinePlaceholder":17},[362,1172,1174,1177,1179,1182,1185,1188,1190,1192],{"class":364,"line":1173},24,[362,1175,1176],{"class":436},"test",[362,1178,593],{"class":377},[362,1180,1181],{"class":384},"\"should always return the same instance of the injectable\"",[362,1183,1184],{"class":377},", (",[362,1186,1187],{"class":446},"t",[362,1189,962],{"class":377},[362,1191,453],{"class":373},[362,1193,456],{"class":377},[362,1195,1197,1200,1203,1205,1208,1211,1214,1216],{"class":364,"line":1196},25,[362,1198,1199],{"class":377},"  t.",[362,1201,1202],{"class":436},"ok",[362,1204,593],{"class":377},[362,1206,1207],{"class":436},"getMySingletonA",[362,1209,1210],{"class":377},"() ",[362,1212,1213],{"class":373},"===",[362,1215,1133],{"class":436},[362,1217,1218],{"class":377},"());\n",[362,1220,1222],{"class":364,"line":1221},26,[362,1223,1224],{"class":377},"});\n",[648,1226,1227],{},[651,1228,1229],{},"If we have a constructor based instantiation (with classes), we only need to wrap the constructor\ninto a function",[353,1231,1233],{"className":355,"code":1232,"language":357,"meta":11,"style":11},"class ServiceA {\n  constructor(deps) {}\n}\n\nconst serviceAFactory = (deps) => new ServiceA(deps);\n",[359,1234,1235,1245,1257,1262,1266],{"__ignoreMap":11},[362,1236,1237,1240,1243],{"class":364,"line":19},[362,1238,1239],{"class":373},"class",[362,1241,1242],{"class":436}," ServiceA",[362,1244,456],{"class":377},[362,1246,1247,1250,1252,1254],{"class":364,"line":12},[362,1248,1249],{"class":373},"  constructor",[362,1251,593],{"class":377},[362,1253,940],{"class":446},[362,1255,1256],{"class":377},") {}\n",[362,1258,1259],{"class":364,"line":391},[362,1260,1261],{"class":377},"}\n",[362,1263,1264],{"class":364,"line":406},[362,1265,424],{"emptyLinePlaceholder":17},[362,1267,1268,1270,1273,1275,1277,1279,1281,1283,1285,1287],{"class":364,"line":421},[362,1269,870],{"class":373},[362,1271,1272],{"class":436}," serviceAFactory",[362,1274,440],{"class":373},[362,1276,572],{"class":377},[362,1278,940],{"class":446},[362,1280,962],{"class":377},[362,1282,453],{"class":373},[362,1284,587],{"class":373},[362,1286,1242],{"class":436},[362,1288,1289],{"class":377},"(deps);\n",[648,1291,1292],{},[651,1293,1294],{},"value function: wraps any constant value into a function",[353,1296,1298],{"className":355,"code":1297,"language":357,"meta":11,"style":11},"const myDep = \"foo\";\n\nconst valueFn = (val) => (whatever) => val;\n\nconst myDepFactory = valueFn(myDep);\n\n\u002F\u002F wich complies with\nimport { test } from \"zora\";\n\ntest(\"should return the constant\", (t) => {\n  t.eq(myDepFactory(), \"foo\");\n});\n",[359,1299,1300,1314,1318,1348,1352,1366,1370,1375,1387,1391,1410,1430],{"__ignoreMap":11},[362,1301,1302,1304,1307,1309,1312],{"class":364,"line":19},[362,1303,870],{"class":373},[362,1305,1306],{"class":465}," myDep",[362,1308,440],{"class":373},[362,1310,1311],{"class":384}," \"foo\"",[362,1313,388],{"class":377},[362,1315,1316],{"class":364,"line":12},[362,1317,424],{"emptyLinePlaceholder":17},[362,1319,1320,1322,1325,1327,1329,1332,1334,1336,1338,1341,1343,1345],{"class":364,"line":391},[362,1321,870],{"class":373},[362,1323,1324],{"class":436}," valueFn",[362,1326,440],{"class":373},[362,1328,572],{"class":377},[362,1330,1331],{"class":446},"val",[362,1333,962],{"class":377},[362,1335,453],{"class":373},[362,1337,572],{"class":377},[362,1339,1340],{"class":446},"whatever",[362,1342,962],{"class":377},[362,1344,453],{"class":373},[362,1346,1347],{"class":377}," val;\n",[362,1349,1350],{"class":364,"line":406},[362,1351,424],{"emptyLinePlaceholder":17},[362,1353,1354,1356,1359,1361,1363],{"class":364,"line":421},[362,1355,870],{"class":373},[362,1357,1358],{"class":465}," myDepFactory",[362,1360,440],{"class":373},[362,1362,1324],{"class":436},[362,1364,1365],{"class":377},"(myDep);\n",[362,1367,1368],{"class":364,"line":427},[362,1369,424],{"emptyLinePlaceholder":17},[362,1371,1372],{"class":364,"line":459},[362,1373,1374],{"class":367},"\u002F\u002F wich complies with\n",[362,1376,1377,1379,1381,1383,1385],{"class":364,"line":477},[362,1378,374],{"class":373},[362,1380,1158],{"class":377},[362,1382,381],{"class":373},[362,1384,1163],{"class":384},[362,1386,388],{"class":377},[362,1388,1389],{"class":364,"line":493},[362,1390,424],{"emptyLinePlaceholder":17},[362,1392,1393,1395,1397,1400,1402,1404,1406,1408],{"class":364,"line":509},[362,1394,1176],{"class":436},[362,1396,593],{"class":377},[362,1398,1399],{"class":384},"\"should return the constant\"",[362,1401,1184],{"class":377},[362,1403,1187],{"class":446},[362,1405,962],{"class":377},[362,1407,453],{"class":373},[362,1409,456],{"class":377},[362,1411,1412,1414,1417,1419,1422,1425,1428],{"class":364,"line":514},[362,1413,1199],{"class":377},[362,1415,1416],{"class":436},"eq",[362,1418,593],{"class":377},[362,1420,1421],{"class":436},"myDepFactory",[362,1423,1424],{"class":377},"(), ",[362,1426,1427],{"class":384},"\"foo\"",[362,1429,599],{"class":377},[362,1431,1432],{"class":364,"line":522},[362,1433,1224],{"class":377},[338,1435,1436],{},"This gives more flexibility over a class system with constructor based instantiation as you can see\nin many popular frameworks nowadays.",[338,1438,1439],{},"How you build or register the injectables factories into the manifest is out of the scope of this\narticle and will depend on the context (going from a plugin system to a set of sophisticated class\nannotations, etc)",[345,1441,1443],{"id":1442},"solving-the-transitive-dependencies-problem-with-meta-programming","Solving the transitive dependencies problem with meta programming",[338,1445,1446],{},"As mentioned in the introduction: if you want a service A, but it depends on a service B which in\nturn depends on a service C, it is difficult to build all the services in the dependency chain.\nBased on the manifest (a flat structure), we can solve the problem of dependency resolution through\nmeta-programming.",[338,1448,1449,1450,1457],{},"Considering that there is no circular dependency, you can model the relationships between the\nservices with a\n",[1451,1452,1456],"a",{"href":1453,"rel":1454},"https:\u002F\u002Fitnext.io\u002Fdo-your-tax-filling-by-using-a-directed-acyclic-graph-ed89682adbd0",[1455],"nofollow","Directed Acyclic Graph","\n(DAG) where the nodes are the services and the vertices represent the “depends on” relationship.",[338,1459,1460,1461,1465],{},"We can leverage property descriptors to build a ",[1462,1463,1464],"em",{},"magic"," object which evaluates lazily the service\nfactories as they are required based on the manifest.",[338,1467,1468],{},"Assuming the following small helper which maps the values of an object to a set of other values",[353,1470,1472],{"className":355,"code":1471,"language":357,"meta":11,"style":11},"const mapValues = (mapFn) => (object) =>\n  Object.fromEntries(Object.entries(object).map(([prop, value]) => [prop, mapFn(value)]));\n\n\u002F\u002F ex\nconst upperCase = mapValues((value) => value.toUpperCase());\n\nupperCase({ foo: \"bar\" });\n\u002F\u002F > { foo: 'BAR' }\n",[359,1473,1474,1502,1546,1550,1555,1583,1587,1601],{"__ignoreMap":11},[362,1475,1476,1478,1481,1483,1485,1488,1490,1492,1494,1497,1499],{"class":364,"line":19},[362,1477,870],{"class":373},[362,1479,1480],{"class":436}," mapValues",[362,1482,440],{"class":373},[362,1484,572],{"class":377},[362,1486,1487],{"class":446},"mapFn",[362,1489,962],{"class":377},[362,1491,453],{"class":373},[362,1493,572],{"class":377},[362,1495,1496],{"class":446},"object",[362,1498,962],{"class":377},[362,1500,1501],{"class":373},"=>\n",[362,1503,1504,1507,1510,1513,1516,1519,1522,1525,1528,1530,1533,1536,1538,1541,1543],{"class":364,"line":12},[362,1505,1506],{"class":377},"  Object.",[362,1508,1509],{"class":436},"fromEntries",[362,1511,1512],{"class":377},"(Object.",[362,1514,1515],{"class":436},"entries",[362,1517,1518],{"class":377},"(object).",[362,1520,1521],{"class":436},"map",[362,1523,1524],{"class":377},"(([",[362,1526,1527],{"class":446},"prop",[362,1529,537],{"class":377},[362,1531,1532],{"class":446},"value",[362,1534,1535],{"class":377},"]) ",[362,1537,453],{"class":373},[362,1539,1540],{"class":377}," [prop, ",[362,1542,1487],{"class":436},[362,1544,1545],{"class":377},"(value)]));\n",[362,1547,1548],{"class":364,"line":391},[362,1549,424],{"emptyLinePlaceholder":17},[362,1551,1552],{"class":364,"line":406},[362,1553,1554],{"class":367},"\u002F\u002F ex\n",[362,1556,1557,1559,1562,1564,1566,1569,1571,1573,1575,1578,1581],{"class":364,"line":421},[362,1558,870],{"class":373},[362,1560,1561],{"class":465}," upperCase",[362,1563,440],{"class":373},[362,1565,1480],{"class":436},[362,1567,1568],{"class":377},"((",[362,1570,1532],{"class":446},[362,1572,962],{"class":377},[362,1574,453],{"class":373},[362,1576,1577],{"class":377}," value.",[362,1579,1580],{"class":436},"toUpperCase",[362,1582,1218],{"class":377},[362,1584,1585],{"class":364,"line":427},[362,1586,424],{"emptyLinePlaceholder":17},[362,1588,1589,1592,1595,1598],{"class":364,"line":459},[362,1590,1591],{"class":436},"upperCase",[362,1593,1594],{"class":377},"({ foo: ",[362,1596,1597],{"class":384},"\"bar\"",[362,1599,1600],{"class":377}," });\n",[362,1602,1603],{"class":364,"line":477},[362,1604,1605],{"class":367},"\u002F\u002F > { foo: 'BAR' }\n",[338,1607,1608],{},"We can build the property descriptors of our magic object",[353,1610,1612],{"className":355,"code":1611,"language":357,"meta":11,"style":11},"export const inject = (injectablesFactoryMap) => {\n  const injectables = {}; \u002F\u002F (1) the object which will hold the injectables\n  const propertyDescriptors = mapValues(createPropertyDescriptor);\n\n  \u002F\u002F (2) we make this object a meta object which will instantiate an injectable whenever a token will be looked up\n  Object.defineProperties(\n    injectables,\n    propertyDescriptors({\n      ...injectablesFactoryMap,\n    }),\n  );\n\n  return injectables;\n\n  function createPropertyDescriptor(factory) {\n    return {\n      get() {\n        return factory(injectables); \u002F\u002F \"injectables\" are injected in every factory so the dependency graph is magically resolved\n      },\n      enumerable: true,\n    };\n  }\n};\n",[359,1613,1614,1635,1649,1663,1667,1672,1682,1687,1695,1703,1708,1713,1717,1724,1728,1744,1750,1758,1771,1776,1787,1792,1797],{"__ignoreMap":11},[362,1615,1616,1618,1620,1622,1624,1626,1629,1631,1633],{"class":364,"line":19},[362,1617,430],{"class":373},[362,1619,433],{"class":373},[362,1621,907],{"class":436},[362,1623,440],{"class":373},[362,1625,572],{"class":377},[362,1627,1628],{"class":446},"injectablesFactoryMap",[362,1630,962],{"class":377},[362,1632,453],{"class":373},[362,1634,456],{"class":377},[362,1636,1637,1639,1641,1643,1646],{"class":364,"line":12},[362,1638,462],{"class":373},[362,1640,902],{"class":465},[362,1642,440],{"class":373},[362,1644,1645],{"class":377}," {}; ",[362,1647,1648],{"class":367},"\u002F\u002F (1) the object which will hold the injectables\n",[362,1650,1651,1653,1656,1658,1660],{"class":364,"line":391},[362,1652,462],{"class":373},[362,1654,1655],{"class":465}," propertyDescriptors",[362,1657,440],{"class":373},[362,1659,1480],{"class":436},[362,1661,1662],{"class":377},"(createPropertyDescriptor);\n",[362,1664,1665],{"class":364,"line":406},[362,1666,424],{"emptyLinePlaceholder":17},[362,1668,1669],{"class":364,"line":421},[362,1670,1671],{"class":367},"  \u002F\u002F (2) we make this object a meta object which will instantiate an injectable whenever a token will be looked up\n",[362,1673,1674,1676,1679],{"class":364,"line":427},[362,1675,1506],{"class":377},[362,1677,1678],{"class":436},"defineProperties",[362,1680,1681],{"class":377},"(\n",[362,1683,1684],{"class":364,"line":459},[362,1685,1686],{"class":377},"    injectables,\n",[362,1688,1689,1692],{"class":364,"line":477},[362,1690,1691],{"class":436},"    propertyDescriptors",[362,1693,1694],{"class":377},"({\n",[362,1696,1697,1700],{"class":364,"line":493},[362,1698,1699],{"class":373},"      ...",[362,1701,1702],{"class":377},"injectablesFactoryMap,\n",[362,1704,1705],{"class":364,"line":509},[362,1706,1707],{"class":377},"    }),\n",[362,1709,1710],{"class":364,"line":514},[362,1711,1712],{"class":377},"  );\n",[362,1714,1715],{"class":364,"line":522},[362,1716,424],{"emptyLinePlaceholder":17},[362,1718,1719,1721],{"class":364,"line":546},[362,1720,517],{"class":373},[362,1722,1723],{"class":377}," injectables;\n",[362,1725,1726],{"class":364,"line":566},[362,1727,424],{"emptyLinePlaceholder":17},[362,1729,1730,1733,1736,1738,1741],{"class":364,"line":581},[362,1731,1732],{"class":373},"  function",[362,1734,1735],{"class":436}," createPropertyDescriptor",[362,1737,593],{"class":377},[362,1739,1740],{"class":446},"factory",[362,1742,1743],{"class":377},") {\n",[362,1745,1746,1748],{"class":364,"line":602},[362,1747,1102],{"class":373},[362,1749,456],{"class":377},[362,1751,1752,1755],{"class":364,"line":608},[362,1753,1754],{"class":436},"      get",[362,1756,1757],{"class":377},"() {\n",[362,1759,1760,1763,1765,1768],{"class":364,"line":628},[362,1761,1762],{"class":373},"        return",[362,1764,953],{"class":436},[362,1766,1767],{"class":377},"(injectables); ",[362,1769,1770],{"class":367},"\u002F\u002F \"injectables\" are injected in every factory so the dependency graph is magically resolved\n",[362,1772,1773],{"class":364,"line":634},[362,1774,1775],{"class":377},"      },\n",[362,1777,1778,1781,1784],{"class":364,"line":640},[362,1779,1780],{"class":377},"      enumerable: ",[362,1782,1783],{"class":465},"true",[362,1785,1786],{"class":377},",\n",[362,1788,1789],{"class":364,"line":1147},[362,1790,1791],{"class":377},"    };\n",[362,1793,1794],{"class":364,"line":1153},[362,1795,1796],{"class":377},"  }\n",[362,1798,1799],{"class":364,"line":1168},[362,1800,643],{"class":377},[1802,1803,1804,1807],"ol",{},[651,1805,1806],{},"We need first to create an empty object which will hold the injectables and will get in every\nfactory when the latter is called.",[651,1808,1809,1810,1813],{},"This meta object keys are the injectables’ tokens and the property getters are overwritten in\nsuch a way that when you look up for a specific injectable (calling the getter), the factory is\ncalled. Interestingly as the factories themselves use the ",[359,1811,1812],{},"injectables"," object they receive, the\nrelevant getters are called as well so that the whole graph is lazily resolved for the factory\ninitially called.",[338,1815,1816],{},"This solves few of the problems:",[648,1818,1819,1822],{},[651,1820,1821],{},"We automatically resolve the transitive dependencies.",[651,1823,1824],{},"You only import the various factories once, when you build the manifest, making all the components\nagnostic of where their dependencies live",[353,1826,1828],{"className":355,"code":1827,"language":357,"meta":11,"style":11},"import { test } from \"zora\";\nimport { inject } from \".\u002Fdi.js\";\n\n\u002F\u002F depends on \"B\"\nconst createServiceA = ({ B }) => {\n  return {\n    foo() {\n      return B.foo();\n    },\n  };\n};\n\n\u002F\u002F depends on \"C\"\nconst createServiceB = ({ C }) => {\n  return {\n    foo() {\n      return C.foo();\n    },\n  };\n};\nconst createServiceC = () => {\n  return {\n    foo() {\n      return \"bar\";\n    },\n  };\n};\n\n\u002F\u002F injectable manifest: map a token to a factory\nconst manifest = {\n  A: createServiceA,\n  B: createServiceB,\n  C: createServiceC,\n};\n\ntest(`resolve transitive dependencies`, (t) => {\n  const { A } = inject(manifest); \u002F\u002F (1) here we call the getter for A\n  t.eq(A.foo(), \"bar\");\n});\n",[359,1829,1830,1842,1856,1860,1865,1885,1891,1898,1914,1918,1922,1926,1930,1935,1955,1961,1967,1980,1984,1988,1992,2008,2014,2020,2029,2033,2037,2042,2047,2053,2065,2071,2077,2083,2088,2093,2113,2137,2158],{"__ignoreMap":11},[362,1831,1832,1834,1836,1838,1840],{"class":364,"line":19},[362,1833,374],{"class":373},[362,1835,1158],{"class":377},[362,1837,381],{"class":373},[362,1839,1163],{"class":384},[362,1841,388],{"class":377},[362,1843,1844,1846,1849,1851,1854],{"class":364,"line":12},[362,1845,374],{"class":373},[362,1847,1848],{"class":377}," { inject } ",[362,1850,381],{"class":373},[362,1852,1853],{"class":384}," \".\u002Fdi.js\"",[362,1855,388],{"class":377},[362,1857,1858],{"class":364,"line":391},[362,1859,424],{"emptyLinePlaceholder":17},[362,1861,1862],{"class":364,"line":406},[362,1863,1864],{"class":367},"\u002F\u002F depends on \"B\"\n",[362,1866,1867,1869,1872,1874,1876,1879,1881,1883],{"class":364,"line":421},[362,1868,870],{"class":373},[362,1870,1871],{"class":436}," createServiceA",[362,1873,440],{"class":373},[362,1875,443],{"class":377},[362,1877,1878],{"class":446},"B",[362,1880,450],{"class":377},[362,1882,453],{"class":373},[362,1884,456],{"class":377},[362,1886,1887,1889],{"class":364,"line":427},[362,1888,517],{"class":373},[362,1890,456],{"class":377},[362,1892,1893,1896],{"class":364,"line":459},[362,1894,1895],{"class":436},"    foo",[362,1897,1757],{"class":377},[362,1899,1900,1902,1905,1908,1911],{"class":364,"line":477},[362,1901,611],{"class":373},[362,1903,1904],{"class":465}," B",[362,1906,1907],{"class":377},".",[362,1909,1910],{"class":436},"foo",[362,1912,1913],{"class":377},"();\n",[362,1915,1916],{"class":364,"line":493},[362,1917,631],{"class":377},[362,1919,1920],{"class":364,"line":509},[362,1921,637],{"class":377},[362,1923,1924],{"class":364,"line":514},[362,1925,643],{"class":377},[362,1927,1928],{"class":364,"line":522},[362,1929,424],{"emptyLinePlaceholder":17},[362,1931,1932],{"class":364,"line":546},[362,1933,1934],{"class":367},"\u002F\u002F depends on \"C\"\n",[362,1936,1937,1939,1942,1944,1946,1949,1951,1953],{"class":364,"line":566},[362,1938,870],{"class":373},[362,1940,1941],{"class":436}," createServiceB",[362,1943,440],{"class":373},[362,1945,443],{"class":377},[362,1947,1948],{"class":446},"C",[362,1950,450],{"class":377},[362,1952,453],{"class":373},[362,1954,456],{"class":377},[362,1956,1957,1959],{"class":364,"line":581},[362,1958,517],{"class":373},[362,1960,456],{"class":377},[362,1962,1963,1965],{"class":364,"line":602},[362,1964,1895],{"class":436},[362,1966,1757],{"class":377},[362,1968,1969,1971,1974,1976,1978],{"class":364,"line":608},[362,1970,611],{"class":373},[362,1972,1973],{"class":465}," C",[362,1975,1907],{"class":377},[362,1977,1910],{"class":436},[362,1979,1913],{"class":377},[362,1981,1982],{"class":364,"line":628},[362,1983,631],{"class":377},[362,1985,1986],{"class":364,"line":634},[362,1987,637],{"class":377},[362,1989,1990],{"class":364,"line":640},[362,1991,643],{"class":377},[362,1993,1994,1996,1999,2001,2004,2006],{"class":364,"line":1147},[362,1995,870],{"class":373},[362,1997,1998],{"class":436}," createServiceC",[362,2000,440],{"class":373},[362,2002,2003],{"class":377}," () ",[362,2005,453],{"class":373},[362,2007,456],{"class":377},[362,2009,2010,2012],{"class":364,"line":1153},[362,2011,517],{"class":373},[362,2013,456],{"class":377},[362,2015,2016,2018],{"class":364,"line":1168},[362,2017,1895],{"class":436},[362,2019,1757],{"class":377},[362,2021,2022,2024,2027],{"class":364,"line":1173},[362,2023,611],{"class":373},[362,2025,2026],{"class":384}," \"bar\"",[362,2028,388],{"class":377},[362,2030,2031],{"class":364,"line":1196},[362,2032,631],{"class":377},[362,2034,2035],{"class":364,"line":1221},[362,2036,637],{"class":377},[362,2038,2040],{"class":364,"line":2039},27,[362,2041,643],{"class":377},[362,2043,2045],{"class":364,"line":2044},28,[362,2046,424],{"emptyLinePlaceholder":17},[362,2048,2050],{"class":364,"line":2049},29,[362,2051,2052],{"class":367},"\u002F\u002F injectable manifest: map a token to a factory\n",[362,2054,2056,2058,2061,2063],{"class":364,"line":2055},30,[362,2057,870],{"class":373},[362,2059,2060],{"class":465}," manifest",[362,2062,440],{"class":373},[362,2064,456],{"class":377},[362,2066,2068],{"class":364,"line":2067},31,[362,2069,2070],{"class":377},"  A: createServiceA,\n",[362,2072,2074],{"class":364,"line":2073},32,[362,2075,2076],{"class":377},"  B: createServiceB,\n",[362,2078,2080],{"class":364,"line":2079},33,[362,2081,2082],{"class":377},"  C: createServiceC,\n",[362,2084,2086],{"class":364,"line":2085},34,[362,2087,643],{"class":377},[362,2089,2091],{"class":364,"line":2090},35,[362,2092,424],{"emptyLinePlaceholder":17},[362,2094,2096,2098,2100,2103,2105,2107,2109,2111],{"class":364,"line":2095},36,[362,2097,1176],{"class":436},[362,2099,593],{"class":377},[362,2101,2102],{"class":384},"`resolve transitive dependencies`",[362,2104,1184],{"class":377},[362,2106,1187],{"class":446},[362,2108,962],{"class":377},[362,2110,453],{"class":373},[362,2112,456],{"class":377},[362,2114,2116,2118,2121,2124,2127,2129,2131,2134],{"class":364,"line":2115},37,[362,2117,462],{"class":373},[362,2119,2120],{"class":377}," { ",[362,2122,2123],{"class":465},"A",[362,2125,2126],{"class":377}," } ",[362,2128,1108],{"class":373},[362,2130,907],{"class":436},[362,2132,2133],{"class":377},"(manifest); ",[362,2135,2136],{"class":367},"\u002F\u002F (1) here we call the getter for A\n",[362,2138,2140,2142,2144,2146,2148,2150,2152,2154,2156],{"class":364,"line":2139},38,[362,2141,1199],{"class":377},[362,2143,1416],{"class":436},[362,2145,593],{"class":377},[362,2147,2123],{"class":465},[362,2149,1907],{"class":377},[362,2151,1910],{"class":436},[362,2153,1424],{"class":377},[362,2155,1597],{"class":384},[362,2157,599],{"class":377},[362,2159,2161],{"class":364,"line":2160},39,[362,2162,1224],{"class":377},[338,2164,2165],{},"The statement (1) creates the dependency graph: when you destructure the meta-object, the getter of\nA is called, which leads to a cascade of calls to the getter of B, then to that of C.",[338,2167,2168,2169,2172,2173,2178],{},"💡 Note we can change the implementation of the ",[359,2170,2171],{},"mapValues"," function to also map properties whose\nkey is a\n",[1451,2174,2177],{"href":2175,"rel":2176},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FSymbol",[1455],"Symbol",".\nThis type of properties can operate as “secret tokens” to make some injectables only injectable to\nwhomever knows or has access to the Symbol: you can’t lookup for a property whose key is a Symbol if\nyou don’t have a reference of that Symbol.",[353,2180,2182],{"className":355,"code":2181,"language":357,"meta":11,"style":11},"test(`Use symbol for tokens`, (t) => {\n  const sym = Symbol(\"foo\");\n  const manifest = {\n    [sym]: valueFn(\"foo\"),\n    canAccessSymbol: ({ [sym]: foo }) => foo,\n    cantAccessSymbol: ({ [Symbol(\"foo\") \u002F* trying to lookup for the symbol *\u002F]: foo }) => foo,\n  };\n  const { canAccessSymbol, cantAccessSymbol } = createInjector(manifest)();\n  t.eq(canAccessSymbol, \"foo\");\n  t.eq(cantAccessSymbol, undefined, \"could not resolve the symbol\");\n});\n",[359,2183,2184,2203,2221,2231,2246,2263,2293,2297,2321,2334,2353],{"__ignoreMap":11},[362,2185,2186,2188,2190,2193,2195,2197,2199,2201],{"class":364,"line":19},[362,2187,1176],{"class":436},[362,2189,593],{"class":377},[362,2191,2192],{"class":384},"`Use symbol for tokens`",[362,2194,1184],{"class":377},[362,2196,1187],{"class":446},[362,2198,962],{"class":377},[362,2200,453],{"class":373},[362,2202,456],{"class":377},[362,2204,2205,2207,2210,2212,2215,2217,2219],{"class":364,"line":12},[362,2206,462],{"class":373},[362,2208,2209],{"class":465}," sym",[362,2211,440],{"class":373},[362,2213,2214],{"class":436}," Symbol",[362,2216,593],{"class":377},[362,2218,1427],{"class":384},[362,2220,599],{"class":377},[362,2222,2223,2225,2227,2229],{"class":364,"line":391},[362,2224,462],{"class":373},[362,2226,2060],{"class":465},[362,2228,440],{"class":373},[362,2230,456],{"class":377},[362,2232,2233,2236,2239,2241,2243],{"class":364,"line":406},[362,2234,2235],{"class":377},"    [sym]: ",[362,2237,2238],{"class":436},"valueFn",[362,2240,593],{"class":377},[362,2242,1427],{"class":384},[362,2244,2245],{"class":377},"),\n",[362,2247,2248,2251,2254,2256,2258,2260],{"class":364,"line":421},[362,2249,2250],{"class":436},"    canAccessSymbol",[362,2252,2253],{"class":377},": ({ [sym]: ",[362,2255,1910],{"class":446},[362,2257,450],{"class":377},[362,2259,453],{"class":373},[362,2261,2262],{"class":377}," foo,\n",[362,2264,2265,2268,2271,2273,2275,2277,2279,2282,2285,2287,2289,2291],{"class":364,"line":427},[362,2266,2267],{"class":436},"    cantAccessSymbol",[362,2269,2270],{"class":377},": ({ [",[362,2272,2177],{"class":436},[362,2274,593],{"class":377},[362,2276,1427],{"class":384},[362,2278,962],{"class":377},[362,2280,2281],{"class":367},"\u002F* trying to lookup for the symbol *\u002F",[362,2283,2284],{"class":377},"]: ",[362,2286,1910],{"class":446},[362,2288,450],{"class":377},[362,2290,453],{"class":373},[362,2292,2262],{"class":377},[362,2294,2295],{"class":364,"line":459},[362,2296,637],{"class":377},[362,2298,2299,2301,2303,2306,2308,2311,2313,2315,2318],{"class":364,"line":477},[362,2300,462],{"class":373},[362,2302,2120],{"class":377},[362,2304,2305],{"class":465},"canAccessSymbol",[362,2307,537],{"class":377},[362,2309,2310],{"class":465},"cantAccessSymbol",[362,2312,2126],{"class":377},[362,2314,1108],{"class":373},[362,2316,2317],{"class":436}," createInjector",[362,2319,2320],{"class":377},"(manifest)();\n",[362,2322,2323,2325,2327,2330,2332],{"class":364,"line":493},[362,2324,1199],{"class":377},[362,2326,1416],{"class":436},[362,2328,2329],{"class":377},"(canAccessSymbol, ",[362,2331,1427],{"class":384},[362,2333,599],{"class":377},[362,2335,2336,2338,2340,2343,2346,2348,2351],{"class":364,"line":509},[362,2337,1199],{"class":377},[362,2339,1416],{"class":436},[362,2341,2342],{"class":377},"(cantAccessSymbol, ",[362,2344,2345],{"class":465},"undefined",[362,2347,537],{"class":377},[362,2349,2350],{"class":384},"\"could not resolve the symbol\"",[362,2352,599],{"class":377},[362,2354,2355],{"class":364,"line":514},[362,2356,1224],{"class":377},[345,2358,2360],{"id":2359},"going-further-make-sure-we-can-swap-injectable-implementation-depending-on-the-context","Going further: make sure we can swap injectable implementation depending on the context",[338,2362,2363,2364,801,2366,2369],{},"The current implementation is fine for all the dependency graphs you already know prior to the\nexecution of the program. However, in practice you will likely have “late binding”: you will only\nknow the implementation of a given injectable to use at run time, based on the execution context. In\nsome cases, you might also want to overwrite the default implementations provided. Remember, when\ndealing with dependency injection you must think with ",[806,2365,808],{},[806,2367,2368],{},"abstract types"," !",[338,2371,2372],{},"For example, in a web server you could bind your injectables to the user related to the current\nincoming request (and as so, avoiding security concerns on who accesses the resources). You can also\nuse a specific injectable implementation depending on the profile of the user, their location, etc.",[338,2374,2375],{},"To solve theses use cases we are going to make our injector a function which can define\u002Foverwrite\nsome specific factories to allow late dependency binding.",[353,2377,2379],{"className":355,"code":2378,"language":357,"meta":11,"style":11},"export const createInjector = (injectableFactoryMap) => {\n  \u002F\u002F (1) The injector is now wrapped within a function\n  return function inject(lateDeps = {}) {\n    const injectables = {};\n    const propertyDescriptors = mapValues(createPropertyDescriptor);\n\n    Object.defineProperties(\n      injectables,\n      propertyDescriptors({\n        ...injectableFactoryMap,\n        ...lateDeps, \u002F\u002F (2) you can overwrite already defined factories or create late bindings\n      }),\n    );\n\n    return injectables;\n\n    function createPropertyDescriptor(factory) {\n      const actualFactory = typeof factory === \"function\" ? factory : valueFn(factory); \u002F\u002F (3) Syntactic sugar\n      return {\n        get() {\n          return actualFactory(injectables);\n        },\n        enumerable: true,\n      };\n    }\n  };\n};\n",[359,2380,2381,2402,2407,2426,2438,2450,2454,2463,2468,2475,2483,2493,2498,2503,2507,2513,2517,2530,2566,2572,2579,2589,2594,2603,2608,2612,2616],{"__ignoreMap":11},[362,2382,2383,2385,2387,2389,2391,2393,2396,2398,2400],{"class":364,"line":19},[362,2384,430],{"class":373},[362,2386,433],{"class":373},[362,2388,2317],{"class":436},[362,2390,440],{"class":373},[362,2392,572],{"class":377},[362,2394,2395],{"class":446},"injectableFactoryMap",[362,2397,962],{"class":377},[362,2399,453],{"class":373},[362,2401,456],{"class":377},[362,2403,2404],{"class":364,"line":12},[362,2405,2406],{"class":367},"  \u002F\u002F (1) The injector is now wrapped within a function\n",[362,2408,2409,2411,2414,2416,2418,2421,2423],{"class":364,"line":391},[362,2410,517],{"class":373},[362,2412,2413],{"class":373}," function",[362,2415,907],{"class":436},[362,2417,593],{"class":377},[362,2419,2420],{"class":446},"lateDeps",[362,2422,440],{"class":373},[362,2424,2425],{"class":377}," {}) {\n",[362,2427,2428,2431,2433,2435],{"class":364,"line":406},[362,2429,2430],{"class":373},"    const",[362,2432,902],{"class":465},[362,2434,440],{"class":373},[362,2436,2437],{"class":377}," {};\n",[362,2439,2440,2442,2444,2446,2448],{"class":364,"line":421},[362,2441,2430],{"class":373},[362,2443,1655],{"class":465},[362,2445,440],{"class":373},[362,2447,1480],{"class":436},[362,2449,1662],{"class":377},[362,2451,2452],{"class":364,"line":427},[362,2453,424],{"emptyLinePlaceholder":17},[362,2455,2456,2459,2461],{"class":364,"line":459},[362,2457,2458],{"class":377},"    Object.",[362,2460,1678],{"class":436},[362,2462,1681],{"class":377},[362,2464,2465],{"class":364,"line":477},[362,2466,2467],{"class":377},"      injectables,\n",[362,2469,2470,2473],{"class":364,"line":493},[362,2471,2472],{"class":436},"      propertyDescriptors",[362,2474,1694],{"class":377},[362,2476,2477,2480],{"class":364,"line":509},[362,2478,2479],{"class":373},"        ...",[362,2481,2482],{"class":377},"injectableFactoryMap,\n",[362,2484,2485,2487,2490],{"class":364,"line":514},[362,2486,2479],{"class":373},[362,2488,2489],{"class":377},"lateDeps, ",[362,2491,2492],{"class":367},"\u002F\u002F (2) you can overwrite already defined factories or create late bindings\n",[362,2494,2495],{"class":364,"line":522},[362,2496,2497],{"class":377},"      }),\n",[362,2499,2500],{"class":364,"line":546},[362,2501,2502],{"class":377},"    );\n",[362,2504,2505],{"class":364,"line":566},[362,2506,424],{"emptyLinePlaceholder":17},[362,2508,2509,2511],{"class":364,"line":581},[362,2510,1102],{"class":373},[362,2512,1723],{"class":377},[362,2514,2515],{"class":364,"line":602},[362,2516,424],{"emptyLinePlaceholder":17},[362,2518,2519,2522,2524,2526,2528],{"class":364,"line":608},[362,2520,2521],{"class":373},"    function",[362,2523,1735],{"class":436},[362,2525,593],{"class":377},[362,2527,1740],{"class":446},[362,2529,1743],{"class":377},[362,2531,2532,2534,2537,2539,2542,2545,2547,2550,2553,2555,2558,2560,2563],{"class":364,"line":628},[362,2533,549],{"class":373},[362,2535,2536],{"class":465}," actualFactory",[362,2538,440],{"class":373},[362,2540,2541],{"class":373}," typeof",[362,2543,2544],{"class":377}," factory ",[362,2546,1213],{"class":373},[362,2548,2549],{"class":384}," \"function\"",[362,2551,2552],{"class":373}," ?",[362,2554,2544],{"class":377},[362,2556,2557],{"class":373},":",[362,2559,1324],{"class":436},[362,2561,2562],{"class":377},"(factory); ",[362,2564,2565],{"class":367},"\u002F\u002F (3) Syntactic sugar\n",[362,2567,2568,2570],{"class":364,"line":634},[362,2569,611],{"class":373},[362,2571,456],{"class":377},[362,2573,2574,2577],{"class":364,"line":640},[362,2575,2576],{"class":436},"        get",[362,2578,1757],{"class":377},[362,2580,2581,2584,2586],{"class":364,"line":1147},[362,2582,2583],{"class":373},"          return",[362,2585,2536],{"class":436},[362,2587,2588],{"class":377},"(injectables);\n",[362,2590,2591],{"class":364,"line":1153},[362,2592,2593],{"class":377},"        },\n",[362,2595,2596,2599,2601],{"class":364,"line":1168},[362,2597,2598],{"class":377},"        enumerable: ",[362,2600,1783],{"class":465},[362,2602,1786],{"class":377},[362,2604,2605],{"class":364,"line":1173},[362,2606,2607],{"class":377},"      };\n",[362,2609,2610],{"class":364,"line":1196},[362,2611,1093],{"class":377},[362,2613,2614],{"class":364,"line":1221},[362,2615,637],{"class":377},[362,2617,2618],{"class":364,"line":2039},[362,2619,643],{"class":377},[338,2621,2622],{},"The main differences are:",[1802,2624,2625,2628,2631],{},[651,2626,2627],{},"We wrap the injector within a function so we can invoke the dependency resolution multiple times",[651,2629,2630],{},"The manifest can be extended or overwritten later on",[651,2632,2633],{},"The manifest now accepts any value which is not a factory function: the injector wraps it\nautomatically (this is just for convenience)",[338,2635,2636],{},"This implementation should comply with the following specifications:",[353,2638,2640],{"className":355,"code":2639,"language":357,"meta":11,"style":11},"import { test } from \"zora\";\nimport { createInjector } from \".\u002Fdi.js\";\n\nconst defaultUser = { name: \"John\" };\n\nconst inject = createInjector({\n  Greeter: ({ user }) => ({\n    greet() {\n      return `Hello ${user.name}`;\n    },\n  }),\n  user: defaultUser,\n});\n\ntest(`Use default injectable instances as provided by the manifest`, (t) => {\n  const { Greeter } = inject();\n  t.eq(Greeter.greet(), \"Hello John\");\n\n  t.ok(Greeter !== inject().Greeter, \"should return a different instance on every invocation\");\n});\n\ntest(`Overwrite dependencies at invocation time`, (t) => {\n  t.eq(inject().Greeter.greet(), \"Hello John\");\n  t.eq(\n    inject({\n      user: {\n        name: \"Bob\",\n      },\n    }).Greeter.greet(),\n    \"Hello Bob\",\n  );\n  t.eq(\n    inject({\n      user: {\n        name: \"Raymond\",\n      },\n    }).Greeter.greet(),\n    \"Hello Raymond\",\n  );\n});\n",[359,2641,2642,2654,2667,2671,2689,2693,2705,2723,2730,2749,2753,2758,2763,2767,2771,2790,2807,2826,2830,2852,2856,2860,2879,2900,2908,2915,2920,2930,2934,2944,2951,2955,2963,2969,2973,2982,2986,2994,3001,3005],{"__ignoreMap":11},[362,2643,2644,2646,2648,2650,2652],{"class":364,"line":19},[362,2645,374],{"class":373},[362,2647,1158],{"class":377},[362,2649,381],{"class":373},[362,2651,1163],{"class":384},[362,2653,388],{"class":377},[362,2655,2656,2658,2661,2663,2665],{"class":364,"line":12},[362,2657,374],{"class":373},[362,2659,2660],{"class":377}," { createInjector } ",[362,2662,381],{"class":373},[362,2664,1853],{"class":384},[362,2666,388],{"class":377},[362,2668,2669],{"class":364,"line":391},[362,2670,424],{"emptyLinePlaceholder":17},[362,2672,2673,2675,2678,2680,2683,2686],{"class":364,"line":406},[362,2674,870],{"class":373},[362,2676,2677],{"class":465}," defaultUser",[362,2679,440],{"class":373},[362,2681,2682],{"class":377}," { name: ",[362,2684,2685],{"class":384},"\"John\"",[362,2687,2688],{"class":377}," };\n",[362,2690,2691],{"class":364,"line":421},[362,2692,424],{"emptyLinePlaceholder":17},[362,2694,2695,2697,2699,2701,2703],{"class":364,"line":427},[362,2696,870],{"class":373},[362,2698,907],{"class":465},[362,2700,440],{"class":373},[362,2702,2317],{"class":436},[362,2704,1694],{"class":377},[362,2706,2707,2710,2713,2716,2718,2720],{"class":364,"line":459},[362,2708,2709],{"class":436},"  Greeter",[362,2711,2712],{"class":377},": ({ ",[362,2714,2715],{"class":446},"user",[362,2717,450],{"class":377},[362,2719,453],{"class":373},[362,2721,2722],{"class":377}," ({\n",[362,2724,2725,2728],{"class":364,"line":477},[362,2726,2727],{"class":436},"    greet",[362,2729,1757],{"class":377},[362,2731,2732,2734,2737,2739,2741,2744,2747],{"class":364,"line":493},[362,2733,611],{"class":373},[362,2735,2736],{"class":384}," `Hello ${",[362,2738,2715],{"class":377},[362,2740,1907],{"class":384},[362,2742,2743],{"class":377},"name",[362,2745,2746],{"class":384},"}`",[362,2748,388],{"class":377},[362,2750,2751],{"class":364,"line":509},[362,2752,631],{"class":377},[362,2754,2755],{"class":364,"line":514},[362,2756,2757],{"class":377},"  }),\n",[362,2759,2760],{"class":364,"line":522},[362,2761,2762],{"class":377},"  user: defaultUser,\n",[362,2764,2765],{"class":364,"line":546},[362,2766,1224],{"class":377},[362,2768,2769],{"class":364,"line":566},[362,2770,424],{"emptyLinePlaceholder":17},[362,2772,2773,2775,2777,2780,2782,2784,2786,2788],{"class":364,"line":581},[362,2774,1176],{"class":436},[362,2776,593],{"class":377},[362,2778,2779],{"class":384},"`Use default injectable instances as provided by the manifest`",[362,2781,1184],{"class":377},[362,2783,1187],{"class":446},[362,2785,962],{"class":377},[362,2787,453],{"class":373},[362,2789,456],{"class":377},[362,2791,2792,2794,2796,2799,2801,2803,2805],{"class":364,"line":602},[362,2793,462],{"class":373},[362,2795,2120],{"class":377},[362,2797,2798],{"class":465},"Greeter",[362,2800,2126],{"class":377},[362,2802,1108],{"class":373},[362,2804,907],{"class":436},[362,2806,1913],{"class":377},[362,2808,2809,2811,2813,2816,2819,2821,2824],{"class":364,"line":608},[362,2810,1199],{"class":377},[362,2812,1416],{"class":436},[362,2814,2815],{"class":377},"(Greeter.",[362,2817,2818],{"class":436},"greet",[362,2820,1424],{"class":377},[362,2822,2823],{"class":384},"\"Hello John\"",[362,2825,599],{"class":377},[362,2827,2828],{"class":364,"line":628},[362,2829,424],{"emptyLinePlaceholder":17},[362,2831,2832,2834,2836,2839,2842,2844,2847,2850],{"class":364,"line":634},[362,2833,1199],{"class":377},[362,2835,1202],{"class":436},[362,2837,2838],{"class":377},"(Greeter ",[362,2840,2841],{"class":373},"!==",[362,2843,907],{"class":436},[362,2845,2846],{"class":377},"().Greeter, ",[362,2848,2849],{"class":384},"\"should return a different instance on every invocation\"",[362,2851,599],{"class":377},[362,2853,2854],{"class":364,"line":640},[362,2855,1224],{"class":377},[362,2857,2858],{"class":364,"line":1147},[362,2859,424],{"emptyLinePlaceholder":17},[362,2861,2862,2864,2866,2869,2871,2873,2875,2877],{"class":364,"line":1153},[362,2863,1176],{"class":436},[362,2865,593],{"class":377},[362,2867,2868],{"class":384},"`Overwrite dependencies at invocation time`",[362,2870,1184],{"class":377},[362,2872,1187],{"class":446},[362,2874,962],{"class":377},[362,2876,453],{"class":373},[362,2878,456],{"class":377},[362,2880,2881,2883,2885,2887,2889,2892,2894,2896,2898],{"class":364,"line":1168},[362,2882,1199],{"class":377},[362,2884,1416],{"class":436},[362,2886,593],{"class":377},[362,2888,916],{"class":436},[362,2890,2891],{"class":377},"().Greeter.",[362,2893,2818],{"class":436},[362,2895,1424],{"class":377},[362,2897,2823],{"class":384},[362,2899,599],{"class":377},[362,2901,2902,2904,2906],{"class":364,"line":1173},[362,2903,1199],{"class":377},[362,2905,1416],{"class":436},[362,2907,1681],{"class":377},[362,2909,2910,2913],{"class":364,"line":1196},[362,2911,2912],{"class":436},"    inject",[362,2914,1694],{"class":377},[362,2916,2917],{"class":364,"line":1221},[362,2918,2919],{"class":377},"      user: {\n",[362,2921,2922,2925,2928],{"class":364,"line":2039},[362,2923,2924],{"class":377},"        name: ",[362,2926,2927],{"class":384},"\"Bob\"",[362,2929,1786],{"class":377},[362,2931,2932],{"class":364,"line":2044},[362,2933,1775],{"class":377},[362,2935,2936,2939,2941],{"class":364,"line":2049},[362,2937,2938],{"class":377},"    }).Greeter.",[362,2940,2818],{"class":436},[362,2942,2943],{"class":377},"(),\n",[362,2945,2946,2949],{"class":364,"line":2055},[362,2947,2948],{"class":384},"    \"Hello Bob\"",[362,2950,1786],{"class":377},[362,2952,2953],{"class":364,"line":2067},[362,2954,1712],{"class":377},[362,2956,2957,2959,2961],{"class":364,"line":2073},[362,2958,1199],{"class":377},[362,2960,1416],{"class":436},[362,2962,1681],{"class":377},[362,2964,2965,2967],{"class":364,"line":2079},[362,2966,2912],{"class":436},[362,2968,1694],{"class":377},[362,2970,2971],{"class":364,"line":2085},[362,2972,2919],{"class":377},[362,2974,2975,2977,2980],{"class":364,"line":2090},[362,2976,2924],{"class":377},[362,2978,2979],{"class":384},"\"Raymond\"",[362,2981,1786],{"class":377},[362,2983,2984],{"class":364,"line":2095},[362,2985,1775],{"class":377},[362,2987,2988,2990,2992],{"class":364,"line":2115},[362,2989,2938],{"class":377},[362,2991,2818],{"class":436},[362,2993,2943],{"class":377},[362,2995,2996,2999],{"class":364,"line":2139},[362,2997,2998],{"class":384},"    \"Hello Raymond\"",[362,3000,1786],{"class":377},[362,3002,3003],{"class":364,"line":2160},[362,3004,1712],{"class":377},[362,3006,3008],{"class":364,"line":3007},40,[362,3009,1224],{"class":377},[345,3011,3013],{"id":3012},"recursivity-injecting-the-injector-function","Recursivity: Injecting the injector function",[338,3015,3016,3017,3020],{},"In some cases, a injectable may need to inject its dependency graph into one of its own functions.\nWe could make that injectable build its own manifest and injector, but that would mean mixing\nseveral responsibilities and leaking implementation details of the injector\u002Fregistration system:\n",[1462,3018,3019],{},"ie"," going backward compared to what we have built so far.",[338,3022,3023],{},"Instead we can simply make sure an injector get injected itself and therefore allows recursive\ncalls.",[338,3025,3026],{},"Let’s see the point with a typical use case:",[338,3028,3029,3030,3035,3036,3041],{},"You have a client to access a database such ",[1451,3031,3034],{"href":3032,"rel":3033},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fpg",[1455],"node-pg"," for\n",[1451,3037,3040],{"href":3038,"rel":3039},"https:\u002F\u002Fwww.postgresql.org\u002F",[1455],"postgresql",". For efficiency, your client will actually be a pool of\nclients which abstracts away the internals.",[353,3043,3045],{"className":355,"code":3044,"language":357,"meta":11,"style":11},"db.query(`SELECT * FROM table`);\n",[359,3046,3047],{"__ignoreMap":11},[362,3048,3049,3052,3054,3056,3059],{"class":364,"line":19},[362,3050,3051],{"class":377},"db.",[362,3053,617],{"class":436},[362,3055,593],{"class":377},[362,3057,3058],{"class":384},"`SELECT * FROM table`",[362,3060,599],{"class":377},[338,3062,3063],{},"When you make such a call you don’t really care whether the client comes from a pool, is already\nconnected, etc. You just want to declare the intention: you want to perform a database query.\nHowever if your intention is to run a SQL transaction the client must be the same, holding a session\nand eventually wrapping the rollback on error etc.",[353,3065,3067],{"className":355,"code":3066,"language":357,"meta":11,"style":11},"import pg from \"pg\";\nimport { createClient } from \".\u002Fclient.js\";\nimport { createClient } from \".\u002Fdb.js\"; \u002F\u002F simple wrapper around the raw driver\n\nexport const createConnectionPool = (conf) => {\n  const pool = new pg.Pool(conf);\n  return {\n    \u002F\u002F ... some db interface\n    \u002F\u002F ...\n    async withinTransaction(fn) {\n      const client = await pool.connect();\n      try {\n        await client.query(\"BEGIN\");\n        const result = await fn({ db: createClient({ client }) });\n        await client.query(\"COMMIT\");\n        return result;\n      } catch (e) {\n        await client.query(\"ROLLBACK\");\n        throw e;\n      } finally {\n        client.release();\n      }\n    },\n  };\n};\n",[359,3068,3069,3083,3097,3113,3117,3137,3157,3163,3168,3173,3186,3206,3213,3230,3253,3268,3275,3286,3301,3308,3317,3327,3331,3335,3339],{"__ignoreMap":11},[362,3070,3071,3073,3076,3078,3081],{"class":364,"line":19},[362,3072,374],{"class":373},[362,3074,3075],{"class":377}," pg ",[362,3077,381],{"class":373},[362,3079,3080],{"class":384}," \"pg\"",[362,3082,388],{"class":377},[362,3084,3085,3087,3090,3092,3095],{"class":364,"line":12},[362,3086,374],{"class":373},[362,3088,3089],{"class":377}," { createClient } ",[362,3091,381],{"class":373},[362,3093,3094],{"class":384}," \".\u002Fclient.js\"",[362,3096,388],{"class":377},[362,3098,3099,3101,3103,3105,3107,3110],{"class":364,"line":391},[362,3100,374],{"class":373},[362,3102,3089],{"class":377},[362,3104,381],{"class":373},[362,3106,385],{"class":384},[362,3108,3109],{"class":377},"; ",[362,3111,3112],{"class":367},"\u002F\u002F simple wrapper around the raw driver\n",[362,3114,3115],{"class":364,"line":406},[362,3116,424],{"emptyLinePlaceholder":17},[362,3118,3119,3121,3123,3125,3127,3129,3131,3133,3135],{"class":364,"line":421},[362,3120,430],{"class":373},[362,3122,433],{"class":373},[362,3124,471],{"class":436},[362,3126,440],{"class":373},[362,3128,572],{"class":377},[362,3130,447],{"class":446},[362,3132,962],{"class":377},[362,3134,453],{"class":373},[362,3136,456],{"class":377},[362,3138,3139,3141,3144,3146,3148,3151,3154],{"class":364,"line":427},[362,3140,462],{"class":373},[362,3142,3143],{"class":465}," pool",[362,3145,440],{"class":373},[362,3147,587],{"class":373},[362,3149,3150],{"class":377}," pg.",[362,3152,3153],{"class":436},"Pool",[362,3155,3156],{"class":377},"(conf);\n",[362,3158,3159,3161],{"class":364,"line":459},[362,3160,517],{"class":373},[362,3162,456],{"class":377},[362,3164,3165],{"class":364,"line":477},[362,3166,3167],{"class":367},"    \u002F\u002F ... some db interface\n",[362,3169,3170],{"class":364,"line":493},[362,3171,3172],{"class":367},"    \u002F\u002F ...\n",[362,3174,3175,3177,3180,3182,3184],{"class":364,"line":509},[362,3176,525],{"class":373},[362,3178,3179],{"class":436}," withinTransaction",[362,3181,593],{"class":377},[362,3183,1046],{"class":446},[362,3185,1743],{"class":377},[362,3187,3188,3190,3193,3195,3198,3201,3204],{"class":364,"line":514},[362,3189,549],{"class":373},[362,3191,3192],{"class":465}," client",[362,3194,440],{"class":373},[362,3196,3197],{"class":373}," await",[362,3199,3200],{"class":377}," pool.",[362,3202,3203],{"class":436},"connect",[362,3205,1913],{"class":377},[362,3207,3208,3211],{"class":364,"line":522},[362,3209,3210],{"class":373},"      try",[362,3212,456],{"class":377},[362,3214,3215,3218,3221,3223,3225,3228],{"class":364,"line":546},[362,3216,3217],{"class":373},"        await",[362,3219,3220],{"class":377}," client.",[362,3222,617],{"class":436},[362,3224,593],{"class":377},[362,3226,3227],{"class":384},"\"BEGIN\"",[362,3229,599],{"class":377},[362,3231,3232,3235,3238,3240,3242,3244,3247,3250],{"class":364,"line":566},[362,3233,3234],{"class":373},"        const",[362,3236,3237],{"class":465}," result",[362,3239,440],{"class":373},[362,3241,3197],{"class":373},[362,3243,1111],{"class":436},[362,3245,3246],{"class":377},"({ db: ",[362,3248,3249],{"class":436},"createClient",[362,3251,3252],{"class":377},"({ client }) });\n",[362,3254,3255,3257,3259,3261,3263,3266],{"class":364,"line":581},[362,3256,3217],{"class":373},[362,3258,3220],{"class":377},[362,3260,617],{"class":436},[362,3262,593],{"class":377},[362,3264,3265],{"class":384},"\"COMMIT\"",[362,3267,599],{"class":377},[362,3269,3270,3272],{"class":364,"line":602},[362,3271,1762],{"class":373},[362,3273,3274],{"class":377}," result;\n",[362,3276,3277,3280,3283],{"class":364,"line":608},[362,3278,3279],{"class":377},"      } ",[362,3281,3282],{"class":373},"catch",[362,3284,3285],{"class":377}," (e) {\n",[362,3287,3288,3290,3292,3294,3296,3299],{"class":364,"line":628},[362,3289,3217],{"class":373},[362,3291,3220],{"class":377},[362,3293,617],{"class":436},[362,3295,593],{"class":377},[362,3297,3298],{"class":384},"\"ROLLBACK\"",[362,3300,599],{"class":377},[362,3302,3303,3305],{"class":364,"line":634},[362,3304,584],{"class":373},[362,3306,3307],{"class":377}," e;\n",[362,3309,3310,3312,3315],{"class":364,"line":640},[362,3311,3279],{"class":377},[362,3313,3314],{"class":373},"finally",[362,3316,456],{"class":377},[362,3318,3319,3322,3325],{"class":364,"line":1147},[362,3320,3321],{"class":377},"        client.",[362,3323,3324],{"class":436},"release",[362,3326,1913],{"class":377},[362,3328,3329],{"class":364,"line":1153},[362,3330,605],{"class":377},[362,3332,3333],{"class":364,"line":1168},[362,3334,631],{"class":377},[362,3336,3337],{"class":364,"line":1173},[362,3338,637],{"class":377},[362,3340,3341],{"class":364,"line":1196},[362,3342,643],{"class":377},[338,3344,3345],{},"You’ll use with a client function as so:",[353,3347,3349],{"className":355,"code":3348,"language":357,"meta":11,"style":11},"await db.withinTransaction(function clientFn({ db }) {\n  \u002F\u002F transaction bound code using the local \"db\" client\n  db.query(query1);\n  db.query(query2); \u002F\u002Fetc\n});\n",[359,3350,3351,3375,3380,3390,3402],{"__ignoreMap":11},[362,3352,3353,3356,3358,3361,3363,3366,3369,3371,3373],{"class":364,"line":19},[362,3354,3355],{"class":373},"await",[362,3357,614],{"class":377},[362,3359,3360],{"class":436},"withinTransaction",[362,3362,593],{"class":377},[362,3364,3365],{"class":373},"function",[362,3367,3368],{"class":436}," clientFn",[362,3370,531],{"class":377},[362,3372,687],{"class":446},[362,3374,543],{"class":377},[362,3376,3377],{"class":364,"line":12},[362,3378,3379],{"class":367},"  \u002F\u002F transaction bound code using the local \"db\" client\n",[362,3381,3382,3385,3387],{"class":364,"line":391},[362,3383,3384],{"class":377},"  db.",[362,3386,617],{"class":436},[362,3388,3389],{"class":377},"(query1);\n",[362,3391,3392,3394,3396,3399],{"class":364,"line":406},[362,3393,3384],{"class":377},[362,3395,617],{"class":436},[362,3397,3398],{"class":377},"(query2); ",[362,3400,3401],{"class":367},"\u002F\u002Fetc\n",[362,3403,3404],{"class":364,"line":421},[362,3405,1224],{"class":377},[338,3407,3408,3409,3411,3412,3415],{},"This is fine for low level calls, but in practice you’ll use higher level services which depend on\nan abstract database client. Therefore, you will have to make sure to bind them to the transaction\nbound ",[359,3410,687],{}," client instance, which imply calling the factories from the ",[359,3413,3414],{},"clientFn"," … and you are now\nfacing the caveats we saw at the beginning of this article.",[353,3417,3419],{"className":355,"code":3418,"language":357,"meta":11,"style":11},"import { createUsersService } from \".\u002Fuser.js\";\nimport { createAuthorizationService } from \".\u002Fauthorization.js\";\n\nawait db.withinTransaction(async function clientFn({ db }) {\n  \u002F\u002F bind services to the transaction session\n  const Users = createUsersService({ db });\n  const Authorization = createAuthorizationService({ Users });\n  \u002F\u002F etc\n});\n",[359,3420,3421,3433,3445,3449,3472,3477,3489,3501,3506],{"__ignoreMap":11},[362,3422,3423,3425,3427,3429,3431],{"class":364,"line":19},[362,3424,374],{"class":373},[362,3426,396],{"class":377},[362,3428,381],{"class":373},[362,3430,401],{"class":384},[362,3432,388],{"class":377},[362,3434,3435,3437,3439,3441,3443],{"class":364,"line":12},[362,3436,374],{"class":373},[362,3438,411],{"class":377},[362,3440,381],{"class":373},[362,3442,416],{"class":384},[362,3444,388],{"class":377},[362,3446,3447],{"class":364,"line":391},[362,3448,424],{"emptyLinePlaceholder":17},[362,3450,3451,3453,3455,3457,3459,3462,3464,3466,3468,3470],{"class":364,"line":406},[362,3452,3355],{"class":373},[362,3454,614],{"class":377},[362,3456,3360],{"class":436},[362,3458,593],{"class":377},[362,3460,3461],{"class":373},"async",[362,3463,2413],{"class":373},[362,3465,3368],{"class":436},[362,3467,531],{"class":377},[362,3469,687],{"class":446},[362,3471,543],{"class":377},[362,3473,3474],{"class":364,"line":421},[362,3475,3476],{"class":367},"  \u002F\u002F bind services to the transaction session\n",[362,3478,3479,3481,3483,3485,3487],{"class":364,"line":427},[362,3480,462],{"class":373},[362,3482,482],{"class":465},[362,3484,440],{"class":373},[362,3486,487],{"class":436},[362,3488,490],{"class":377},[362,3490,3491,3493,3495,3497,3499],{"class":364,"line":459},[362,3492,462],{"class":373},[362,3494,498],{"class":465},[362,3496,440],{"class":373},[362,3498,503],{"class":436},[362,3500,506],{"class":377},[362,3502,3503],{"class":364,"line":477},[362,3504,3505],{"class":367},"  \u002F\u002F etc\n",[362,3507,3508],{"class":364,"line":493},[362,3509,1224],{"class":377},[338,3511,3512],{},"With the following implementation of the injector",[353,3514,3516],{"className":355,"code":3515,"language":357,"meta":11,"style":11},"export constcreateInjector= (injectableFactoryMap) =>\n\u002F\u002F (1) the returned function is named \"inject\"\n  function inject(args = {}) {\n    \u002F\u002F ...\n    Object.defineProperties(\n      injectables,\n      propertyDescriptors({\n        ...injectableFactoryMap,\n        inject: valueFn(inject), \u002F\u002F (2) we inject the \"inject\" function !\n        ...args,\n      })\n    );\n    \u002F\u002F ...\n  };\n\n",[359,3517,3518,3535,3540,3555,3559,3567,3571,3577,3583,3596,3603,3608,3612,3616],{"__ignoreMap":11},[362,3519,3520,3522,3525,3527,3529,3531,3533],{"class":364,"line":19},[362,3521,430],{"class":373},[362,3523,3524],{"class":436}," constcreateInjector",[362,3526,1108],{"class":373},[362,3528,572],{"class":377},[362,3530,2395],{"class":446},[362,3532,962],{"class":377},[362,3534,1501],{"class":373},[362,3536,3537],{"class":364,"line":12},[362,3538,3539],{"class":367},"\u002F\u002F (1) the returned function is named \"inject\"\n",[362,3541,3542,3544,3546,3548,3551,3553],{"class":364,"line":391},[362,3543,1732],{"class":373},[362,3545,907],{"class":436},[362,3547,593],{"class":377},[362,3549,3550],{"class":446},"args",[362,3552,440],{"class":373},[362,3554,2425],{"class":377},[362,3556,3557],{"class":364,"line":406},[362,3558,3172],{"class":367},[362,3560,3561,3563,3565],{"class":364,"line":421},[362,3562,2458],{"class":377},[362,3564,1678],{"class":436},[362,3566,1681],{"class":377},[362,3568,3569],{"class":364,"line":427},[362,3570,2467],{"class":377},[362,3572,3573,3575],{"class":364,"line":459},[362,3574,2472],{"class":436},[362,3576,1694],{"class":377},[362,3578,3579,3581],{"class":364,"line":477},[362,3580,2479],{"class":373},[362,3582,2482],{"class":377},[362,3584,3585,3588,3590,3593],{"class":364,"line":493},[362,3586,3587],{"class":377},"        inject: ",[362,3589,2238],{"class":436},[362,3591,3592],{"class":377},"(inject), ",[362,3594,3595],{"class":367},"\u002F\u002F (2) we inject the \"inject\" function !\n",[362,3597,3598,3600],{"class":364,"line":509},[362,3599,2479],{"class":373},[362,3601,3602],{"class":377},"args,\n",[362,3604,3605],{"class":364,"line":514},[362,3606,3607],{"class":377},"      })\n",[362,3609,3610],{"class":364,"line":522},[362,3611,2502],{"class":377},[362,3613,3614],{"class":364,"line":546},[362,3615,3172],{"class":367},[362,3617,3618],{"class":364,"line":566},[362,3619,637],{"class":377},[338,3621,3622],{},"You are now able to recursively call the inject function as it is added to the dependency graph (2):",[353,3624,3626],{"className":355,"code":3625,"language":357,"meta":11,"style":11},"const bindToInjectables =\n  (db) =>\n  \u002F\u002F (1)\n  ({ inject }) => ({\n    ...db,\n    \u002F\u002F (2) overwrite the implementation of the db \"withinTransaction\" method\n    withinTransaction: (fn) =>\n      \u002F\u002F (3) delagate to the actual implementation ...\n      db.withinTransaction(({ db }) =>\n        \u002F\u002F (4) but calling the client function with the injectables bound to the transaction client\n        fn(\n          inject({\n            db: bindToInjectables(db),\n          }),\n        ),\n      ),\n  });\n\n\u002F\u002F ...\nconst inject = createInjector(manifest);\n\n\u002F\u002F ...\n\u002F\u002F const db = getting db from somewhere\nconst injectables = inject({ db: bindToInjectables(db) });\n",[359,3627,3628,3638,3649,3654,3667,3675,3680,3694,3699,3715,3720,3727,3734,3745,3750,3755,3760,3765,3769,3774,3787,3791,3795,3800],{"__ignoreMap":11},[362,3629,3630,3632,3635],{"class":364,"line":19},[362,3631,870],{"class":373},[362,3633,3634],{"class":465}," bindToInjectables",[362,3636,3637],{"class":373}," =\n",[362,3639,3640,3643,3645,3647],{"class":364,"line":12},[362,3641,3642],{"class":377},"  (",[362,3644,687],{"class":446},[362,3646,962],{"class":377},[362,3648,1501],{"class":373},[362,3650,3651],{"class":364,"line":391},[362,3652,3653],{"class":367},"  \u002F\u002F (1)\n",[362,3655,3656,3659,3661,3663,3665],{"class":364,"line":406},[362,3657,3658],{"class":377},"  ({ ",[362,3660,916],{"class":446},[362,3662,450],{"class":377},[362,3664,453],{"class":373},[362,3666,2722],{"class":377},[362,3668,3669,3672],{"class":364,"line":421},[362,3670,3671],{"class":373},"    ...",[362,3673,3674],{"class":377},"db,\n",[362,3676,3677],{"class":364,"line":427},[362,3678,3679],{"class":367},"    \u002F\u002F (2) overwrite the implementation of the db \"withinTransaction\" method\n",[362,3681,3682,3685,3688,3690,3692],{"class":364,"line":459},[362,3683,3684],{"class":436},"    withinTransaction",[362,3686,3687],{"class":377},": (",[362,3689,1046],{"class":446},[362,3691,962],{"class":377},[362,3693,1501],{"class":373},[362,3695,3696],{"class":364,"line":477},[362,3697,3698],{"class":367},"      \u002F\u002F (3) delagate to the actual implementation ...\n",[362,3700,3701,3704,3706,3709,3711,3713],{"class":364,"line":493},[362,3702,3703],{"class":377},"      db.",[362,3705,3360],{"class":436},[362,3707,3708],{"class":377},"(({ ",[362,3710,687],{"class":446},[362,3712,450],{"class":377},[362,3714,1501],{"class":373},[362,3716,3717],{"class":364,"line":509},[362,3718,3719],{"class":367},"        \u002F\u002F (4) but calling the client function with the injectables bound to the transaction client\n",[362,3721,3722,3725],{"class":364,"line":514},[362,3723,3724],{"class":436},"        fn",[362,3726,1681],{"class":377},[362,3728,3729,3732],{"class":364,"line":522},[362,3730,3731],{"class":436},"          inject",[362,3733,1694],{"class":377},[362,3735,3736,3739,3742],{"class":364,"line":546},[362,3737,3738],{"class":377},"            db: ",[362,3740,3741],{"class":436},"bindToInjectables",[362,3743,3744],{"class":377},"(db),\n",[362,3746,3747],{"class":364,"line":566},[362,3748,3749],{"class":377},"          }),\n",[362,3751,3752],{"class":364,"line":581},[362,3753,3754],{"class":377},"        ),\n",[362,3756,3757],{"class":364,"line":602},[362,3758,3759],{"class":377},"      ),\n",[362,3761,3762],{"class":364,"line":608},[362,3763,3764],{"class":377},"  });\n",[362,3766,3767],{"class":364,"line":628},[362,3768,424],{"emptyLinePlaceholder":17},[362,3770,3771],{"class":364,"line":634},[362,3772,3773],{"class":367},"\u002F\u002F ...\n",[362,3775,3776,3778,3780,3782,3784],{"class":364,"line":640},[362,3777,870],{"class":373},[362,3779,907],{"class":465},[362,3781,440],{"class":373},[362,3783,2317],{"class":436},[362,3785,3786],{"class":377},"(manifest);\n",[362,3788,3789],{"class":364,"line":1147},[362,3790,424],{"emptyLinePlaceholder":17},[362,3792,3793],{"class":364,"line":1153},[362,3794,3773],{"class":367},[362,3796,3797],{"class":364,"line":1168},[362,3798,3799],{"class":367},"\u002F\u002F const db = getting db from somewhere\n",[362,3801,3802,3804,3806,3808,3810,3812,3814],{"class":364,"line":1173},[362,3803,870],{"class":373},[362,3805,902],{"class":465},[362,3807,440],{"class":373},[362,3809,907],{"class":436},[362,3811,3246],{"class":377},[362,3813,3741],{"class":436},[362,3815,3816],{"class":377},"(db) });\n",[338,3818,3819,3820,3822,3823,3825],{},"The function ",[359,3821,3741],{}," takes a ",[359,3824,687],{}," object and returns a new factory to pass to a manifest\nor to the inject function for late binding:",[1802,3827,3828,3831,3837,3842],{},[651,3829,3830],{},"As any registered factory it gets the injectables… including the inject function itself",[651,3832,3833,3834,3836],{},"we overwrite the provided ",[359,3835,687],{}," instance",[651,3838,3839,3841],{},[359,3840,3360],{}," delegates the call",[651,3843,3844,3845,3847],{},"calling the client function with all the dependencies where ",[359,3846,687],{}," refers here to the transaction\nbound client.",[353,3849,3851],{"className":355,"code":3850,"language":357,"meta":11,"style":11},"import { test } from \"zora\";\nimport { createInjector } from \".\u002Flib\u002Fdi\u002Finjector.js\";\n\nconst createDB = (depth = 0) => {\n  return {\n    depth,\n    withinTransaction: (fn) => {\n      return fn({ db: createDB(depth + 1) });\n    },\n  };\n};\n\nconst serviceFactory = ({ db }) => {\n  return {\n    foo() {\n      return db.depth;\n    },\n  };\n};\n\nconst inject = createInjector({\n  A: serviceFactory,\n});\n\ntest(\"withinTransaction should scope the clientFn to a given db instance\", (t) => {\n  const { A, db } = inject({ db: createDB() });\n  t.eq(A.foo(), 0, \"should have the default depth\");\n  t.eq(\n    db.withinTransaction(({ db }) => {\n      return serviceFactory({ db }).foo();\n    }),\n    1,\n    \"child db client\",\n  );\n});\n\ntest(\"Injector binds clientFn to the local db context\", (t) => {\n  const bindToInjectables =\n    (db) =>\n    ({ inject }) => {\n      return {\n        ...db,\n        withinTransaction: (fn) =>\n          db.withinTransaction(({ db }) => {\n            return fn(\n              inject({\n                db: bindToInjectables(db),\n              }),\n            );\n          }),\n      };\n    };\n\n  const { A, db } = inject({ db: bindToInjectables(createDB()) });\n  t.eq(A.foo(), 0, \"should have the default depth\");\n  t.eq(\n    \u002F\u002F A is injected into the transaction function\n    db.withinTransaction(({ A }) => {\n      return A.foo();\n    }),\n    1,\n    \"local A is bound to child client (depth 1)\",\n  );\n});\n",[359,3852,3853,3865,3878,3882,3907,3913,3918,3932,3955,3959,3963,3967,3971,3990,3996,4002,4009,4013,4017,4021,4025,4037,4042,4046,4050,4069,4094,4120,4128,4145,4158,4162,4169,4176,4180,4184,4188,4207,4215,4226,4239,4246,4253,4267,4285,4295,4303,4313,4319,4325,4330,4335,4340,4345,4375,4400,4409,4415,4432,4446,4451,4458,4466,4471],{"__ignoreMap":11},[362,3854,3855,3857,3859,3861,3863],{"class":364,"line":19},[362,3856,374],{"class":373},[362,3858,1158],{"class":377},[362,3860,381],{"class":373},[362,3862,1163],{"class":384},[362,3864,388],{"class":377},[362,3866,3867,3869,3871,3873,3876],{"class":364,"line":12},[362,3868,374],{"class":373},[362,3870,2660],{"class":377},[362,3872,381],{"class":373},[362,3874,3875],{"class":384}," \".\u002Flib\u002Fdi\u002Finjector.js\"",[362,3877,388],{"class":377},[362,3879,3880],{"class":364,"line":391},[362,3881,424],{"emptyLinePlaceholder":17},[362,3883,3884,3886,3889,3891,3893,3896,3898,3901,3903,3905],{"class":364,"line":406},[362,3885,870],{"class":373},[362,3887,3888],{"class":436}," createDB",[362,3890,440],{"class":373},[362,3892,572],{"class":377},[362,3894,3895],{"class":446},"depth",[362,3897,440],{"class":373},[362,3899,3900],{"class":465}," 0",[362,3902,962],{"class":377},[362,3904,453],{"class":373},[362,3906,456],{"class":377},[362,3908,3909,3911],{"class":364,"line":421},[362,3910,517],{"class":373},[362,3912,456],{"class":377},[362,3914,3915],{"class":364,"line":427},[362,3916,3917],{"class":377},"    depth,\n",[362,3919,3920,3922,3924,3926,3928,3930],{"class":364,"line":459},[362,3921,3684],{"class":436},[362,3923,3687],{"class":377},[362,3925,1046],{"class":446},[362,3927,962],{"class":377},[362,3929,453],{"class":373},[362,3931,456],{"class":377},[362,3933,3934,3936,3938,3940,3943,3946,3949,3952],{"class":364,"line":477},[362,3935,611],{"class":373},[362,3937,1111],{"class":436},[362,3939,3246],{"class":377},[362,3941,3942],{"class":436},"createDB",[362,3944,3945],{"class":377},"(depth ",[362,3947,3948],{"class":373},"+",[362,3950,3951],{"class":465}," 1",[362,3953,3954],{"class":377},") });\n",[362,3956,3957],{"class":364,"line":493},[362,3958,631],{"class":377},[362,3960,3961],{"class":364,"line":509},[362,3962,637],{"class":377},[362,3964,3965],{"class":364,"line":514},[362,3966,643],{"class":377},[362,3968,3969],{"class":364,"line":522},[362,3970,424],{"emptyLinePlaceholder":17},[362,3972,3973,3975,3978,3980,3982,3984,3986,3988],{"class":364,"line":546},[362,3974,870],{"class":373},[362,3976,3977],{"class":436}," serviceFactory",[362,3979,440],{"class":373},[362,3981,443],{"class":377},[362,3983,687],{"class":446},[362,3985,450],{"class":377},[362,3987,453],{"class":373},[362,3989,456],{"class":377},[362,3991,3992,3994],{"class":364,"line":566},[362,3993,517],{"class":373},[362,3995,456],{"class":377},[362,3997,3998,4000],{"class":364,"line":581},[362,3999,1895],{"class":436},[362,4001,1757],{"class":377},[362,4003,4004,4006],{"class":364,"line":602},[362,4005,611],{"class":373},[362,4007,4008],{"class":377}," db.depth;\n",[362,4010,4011],{"class":364,"line":608},[362,4012,631],{"class":377},[362,4014,4015],{"class":364,"line":628},[362,4016,637],{"class":377},[362,4018,4019],{"class":364,"line":634},[362,4020,643],{"class":377},[362,4022,4023],{"class":364,"line":640},[362,4024,424],{"emptyLinePlaceholder":17},[362,4026,4027,4029,4031,4033,4035],{"class":364,"line":1147},[362,4028,870],{"class":373},[362,4030,907],{"class":465},[362,4032,440],{"class":373},[362,4034,2317],{"class":436},[362,4036,1694],{"class":377},[362,4038,4039],{"class":364,"line":1153},[362,4040,4041],{"class":377},"  A: serviceFactory,\n",[362,4043,4044],{"class":364,"line":1168},[362,4045,1224],{"class":377},[362,4047,4048],{"class":364,"line":1173},[362,4049,424],{"emptyLinePlaceholder":17},[362,4051,4052,4054,4056,4059,4061,4063,4065,4067],{"class":364,"line":1196},[362,4053,1176],{"class":436},[362,4055,593],{"class":377},[362,4057,4058],{"class":384},"\"withinTransaction should scope the clientFn to a given db instance\"",[362,4060,1184],{"class":377},[362,4062,1187],{"class":446},[362,4064,962],{"class":377},[362,4066,453],{"class":373},[362,4068,456],{"class":377},[362,4070,4071,4073,4075,4077,4079,4081,4083,4085,4087,4089,4091],{"class":364,"line":1221},[362,4072,462],{"class":373},[362,4074,2120],{"class":377},[362,4076,2123],{"class":465},[362,4078,537],{"class":377},[362,4080,687],{"class":465},[362,4082,2126],{"class":377},[362,4084,1108],{"class":373},[362,4086,907],{"class":436},[362,4088,3246],{"class":377},[362,4090,3942],{"class":436},[362,4092,4093],{"class":377},"() });\n",[362,4095,4096,4098,4100,4102,4104,4106,4108,4110,4113,4115,4118],{"class":364,"line":2039},[362,4097,1199],{"class":377},[362,4099,1416],{"class":436},[362,4101,593],{"class":377},[362,4103,2123],{"class":465},[362,4105,1907],{"class":377},[362,4107,1910],{"class":436},[362,4109,1424],{"class":377},[362,4111,4112],{"class":465},"0",[362,4114,537],{"class":377},[362,4116,4117],{"class":384},"\"should have the default depth\"",[362,4119,599],{"class":377},[362,4121,4122,4124,4126],{"class":364,"line":2044},[362,4123,1199],{"class":377},[362,4125,1416],{"class":436},[362,4127,1681],{"class":377},[362,4129,4130,4133,4135,4137,4139,4141,4143],{"class":364,"line":2049},[362,4131,4132],{"class":377},"    db.",[362,4134,3360],{"class":436},[362,4136,3708],{"class":377},[362,4138,687],{"class":446},[362,4140,450],{"class":377},[362,4142,453],{"class":373},[362,4144,456],{"class":377},[362,4146,4147,4149,4151,4154,4156],{"class":364,"line":2055},[362,4148,611],{"class":373},[362,4150,3977],{"class":436},[362,4152,4153],{"class":377},"({ db }).",[362,4155,1910],{"class":436},[362,4157,1913],{"class":377},[362,4159,4160],{"class":364,"line":2067},[362,4161,1707],{"class":377},[362,4163,4164,4167],{"class":364,"line":2073},[362,4165,4166],{"class":465},"    1",[362,4168,1786],{"class":377},[362,4170,4171,4174],{"class":364,"line":2079},[362,4172,4173],{"class":384},"    \"child db client\"",[362,4175,1786],{"class":377},[362,4177,4178],{"class":364,"line":2085},[362,4179,1712],{"class":377},[362,4181,4182],{"class":364,"line":2090},[362,4183,1224],{"class":377},[362,4185,4186],{"class":364,"line":2095},[362,4187,424],{"emptyLinePlaceholder":17},[362,4189,4190,4192,4194,4197,4199,4201,4203,4205],{"class":364,"line":2115},[362,4191,1176],{"class":436},[362,4193,593],{"class":377},[362,4195,4196],{"class":384},"\"Injector binds clientFn to the local db context\"",[362,4198,1184],{"class":377},[362,4200,1187],{"class":446},[362,4202,962],{"class":377},[362,4204,453],{"class":373},[362,4206,456],{"class":377},[362,4208,4209,4211,4213],{"class":364,"line":2139},[362,4210,462],{"class":373},[362,4212,3634],{"class":465},[362,4214,3637],{"class":373},[362,4216,4217,4220,4222,4224],{"class":364,"line":2160},[362,4218,4219],{"class":377},"    (",[362,4221,687],{"class":446},[362,4223,962],{"class":377},[362,4225,1501],{"class":373},[362,4227,4228,4231,4233,4235,4237],{"class":364,"line":3007},[362,4229,4230],{"class":377},"    ({ ",[362,4232,916],{"class":446},[362,4234,450],{"class":377},[362,4236,453],{"class":373},[362,4238,456],{"class":377},[362,4240,4242,4244],{"class":364,"line":4241},41,[362,4243,611],{"class":373},[362,4245,456],{"class":377},[362,4247,4249,4251],{"class":364,"line":4248},42,[362,4250,2479],{"class":373},[362,4252,3674],{"class":377},[362,4254,4256,4259,4261,4263,4265],{"class":364,"line":4255},43,[362,4257,4258],{"class":436},"        withinTransaction",[362,4260,3687],{"class":377},[362,4262,1046],{"class":446},[362,4264,962],{"class":377},[362,4266,1501],{"class":373},[362,4268,4270,4273,4275,4277,4279,4281,4283],{"class":364,"line":4269},44,[362,4271,4272],{"class":377},"          db.",[362,4274,3360],{"class":436},[362,4276,3708],{"class":377},[362,4278,687],{"class":446},[362,4280,450],{"class":377},[362,4282,453],{"class":373},[362,4284,456],{"class":377},[362,4286,4288,4291,4293],{"class":364,"line":4287},45,[362,4289,4290],{"class":373},"            return",[362,4292,1111],{"class":436},[362,4294,1681],{"class":377},[362,4296,4298,4301],{"class":364,"line":4297},46,[362,4299,4300],{"class":436},"              inject",[362,4302,1694],{"class":377},[362,4304,4306,4309,4311],{"class":364,"line":4305},47,[362,4307,4308],{"class":377},"                db: ",[362,4310,3741],{"class":436},[362,4312,3744],{"class":377},[362,4314,4316],{"class":364,"line":4315},48,[362,4317,4318],{"class":377},"              }),\n",[362,4320,4322],{"class":364,"line":4321},49,[362,4323,4324],{"class":377},"            );\n",[362,4326,4328],{"class":364,"line":4327},50,[362,4329,3749],{"class":377},[362,4331,4333],{"class":364,"line":4332},51,[362,4334,2607],{"class":377},[362,4336,4338],{"class":364,"line":4337},52,[362,4339,1791],{"class":377},[362,4341,4343],{"class":364,"line":4342},53,[362,4344,424],{"emptyLinePlaceholder":17},[362,4346,4348,4350,4352,4354,4356,4358,4360,4362,4364,4366,4368,4370,4372],{"class":364,"line":4347},54,[362,4349,462],{"class":373},[362,4351,2120],{"class":377},[362,4353,2123],{"class":465},[362,4355,537],{"class":377},[362,4357,687],{"class":465},[362,4359,2126],{"class":377},[362,4361,1108],{"class":373},[362,4363,907],{"class":436},[362,4365,3246],{"class":377},[362,4367,3741],{"class":436},[362,4369,593],{"class":377},[362,4371,3942],{"class":436},[362,4373,4374],{"class":377},"()) });\n",[362,4376,4378,4380,4382,4384,4386,4388,4390,4392,4394,4396,4398],{"class":364,"line":4377},55,[362,4379,1199],{"class":377},[362,4381,1416],{"class":436},[362,4383,593],{"class":377},[362,4385,2123],{"class":465},[362,4387,1907],{"class":377},[362,4389,1910],{"class":436},[362,4391,1424],{"class":377},[362,4393,4112],{"class":465},[362,4395,537],{"class":377},[362,4397,4117],{"class":384},[362,4399,599],{"class":377},[362,4401,4403,4405,4407],{"class":364,"line":4402},56,[362,4404,1199],{"class":377},[362,4406,1416],{"class":436},[362,4408,1681],{"class":377},[362,4410,4412],{"class":364,"line":4411},57,[362,4413,4414],{"class":367},"    \u002F\u002F A is injected into the transaction function\n",[362,4416,4418,4420,4422,4424,4426,4428,4430],{"class":364,"line":4417},58,[362,4419,4132],{"class":377},[362,4421,3360],{"class":436},[362,4423,3708],{"class":377},[362,4425,2123],{"class":446},[362,4427,450],{"class":377},[362,4429,453],{"class":373},[362,4431,456],{"class":377},[362,4433,4435,4437,4440,4442,4444],{"class":364,"line":4434},59,[362,4436,611],{"class":373},[362,4438,4439],{"class":465}," A",[362,4441,1907],{"class":377},[362,4443,1910],{"class":436},[362,4445,1913],{"class":377},[362,4447,4449],{"class":364,"line":4448},60,[362,4450,1707],{"class":377},[362,4452,4454,4456],{"class":364,"line":4453},61,[362,4455,4166],{"class":465},[362,4457,1786],{"class":377},[362,4459,4461,4464],{"class":364,"line":4460},62,[362,4462,4463],{"class":384},"    \"local A is bound to child client (depth 1)\"",[362,4465,1786],{"class":377},[362,4467,4469],{"class":364,"line":4468},63,[362,4470,1712],{"class":377},[362,4472,4474],{"class":364,"line":4473},64,[362,4475,1224],{"class":377},[345,4477,4479],{"id":4478},"icing-on-the-cake-improve-the-dev-experience","Icing on the cake: improve the dev experience",[338,4481,4482],{},"We have already improved the developer experience by giving the ability to inject anything (not only\na factory function). But the current component can fail if there is a missing dependency giving a\nquite unhelpful error:",[353,4484,4486],{"className":355,"code":4485,"language":357,"meta":11,"style":11},"import { createInjector } from \".\u002Flib\u002Fdi\u002Finjector.js\";\n\nconst injector = createInjector({});\n\nconst { A } = injector();\n\nA.foo(); \u002F\u002F BOOM: Cannot read properties of undefined (reading 'foo')\n",[359,4487,4488,4500,4504,4518,4522,4538,4542],{"__ignoreMap":11},[362,4489,4490,4492,4494,4496,4498],{"class":364,"line":19},[362,4491,374],{"class":373},[362,4493,2660],{"class":377},[362,4495,381],{"class":373},[362,4497,3875],{"class":384},[362,4499,388],{"class":377},[362,4501,4502],{"class":364,"line":12},[362,4503,424],{"emptyLinePlaceholder":17},[362,4505,4506,4508,4511,4513,4515],{"class":364,"line":391},[362,4507,870],{"class":373},[362,4509,4510],{"class":465}," injector",[362,4512,440],{"class":373},[362,4514,2317],{"class":436},[362,4516,4517],{"class":377},"({});\n",[362,4519,4520],{"class":364,"line":406},[362,4521,424],{"emptyLinePlaceholder":17},[362,4523,4524,4526,4528,4530,4532,4534,4536],{"class":364,"line":421},[362,4525,870],{"class":373},[362,4527,2120],{"class":377},[362,4529,2123],{"class":465},[362,4531,2126],{"class":377},[362,4533,1108],{"class":373},[362,4535,4510],{"class":436},[362,4537,1913],{"class":377},[362,4539,4540],{"class":364,"line":427},[362,4541,424],{"emptyLinePlaceholder":17},[362,4543,4544,4546,4548,4550,4553],{"class":364,"line":459},[362,4545,2123],{"class":465},[362,4547,1907],{"class":377},[362,4549,1910],{"class":436},[362,4551,4552],{"class":377},"(); ",[362,4554,4555],{"class":367},"\u002F\u002F BOOM: Cannot read properties of undefined (reading 'foo')\n",[338,4557,4558],{},"By using a proxy we can trap the getters’ calls and detect if a token does not exist in the\ndependency graph, giving a more helpful feedback to the developer.",[353,4560,4562],{"className":355,"code":4561,"language":357,"meta":11,"style":11},"export const createInjector = (injectableFactoryMap) =>\n  function inject(args = {}) {\n    const target = {};\n\n    \u002F\u002F (1) injectables is now a proxy\n    const injectables = new Proxy(target, {\n      get(target, prop, receiver) {\n        if (!(prop in target)) {\n          throw new Error(`could not resolve factory '${prop.toString()}'`);\n        }\n        return Reflect.get(target, prop, receiver);\n      },\n    });\n\n    const propertyDescriptors = mapValues(createPropertyDescriptor);\n\n    Object.defineProperties(\n      target,\n      propertyDescriptors({\n        ...injectableFactoryMap,\n        inject: valueFn(inject),\n        ...args,\n      }),\n    );\n\n    return injectables;\n\n    function createPropertyDescriptor(factory) {\n      const actualFactory = typeof factory === \"function\" ? factory : valueFn(factory);\n      return {\n        get() {\n          return actualFactory(injectables);\n        },\n        enumerable: true,\n      };\n    }\n  };\n",[359,4563,4564,4582,4596,4607,4611,4616,4632,4652,4670,4699,4704,4717,4721,4726,4730,4742,4746,4754,4759,4765,4771,4780,4786,4790,4794,4798,4804,4808,4820,4847,4853,4859,4867,4871,4879,4883,4887],{"__ignoreMap":11},[362,4565,4566,4568,4570,4572,4574,4576,4578,4580],{"class":364,"line":19},[362,4567,430],{"class":373},[362,4569,433],{"class":373},[362,4571,2317],{"class":436},[362,4573,440],{"class":373},[362,4575,572],{"class":377},[362,4577,2395],{"class":446},[362,4579,962],{"class":377},[362,4581,1501],{"class":373},[362,4583,4584,4586,4588,4590,4592,4594],{"class":364,"line":12},[362,4585,1732],{"class":373},[362,4587,907],{"class":436},[362,4589,593],{"class":377},[362,4591,3550],{"class":446},[362,4593,440],{"class":373},[362,4595,2425],{"class":377},[362,4597,4598,4600,4603,4605],{"class":364,"line":391},[362,4599,2430],{"class":373},[362,4601,4602],{"class":465}," target",[362,4604,440],{"class":373},[362,4606,2437],{"class":377},[362,4608,4609],{"class":364,"line":406},[362,4610,424],{"emptyLinePlaceholder":17},[362,4612,4613],{"class":364,"line":421},[362,4614,4615],{"class":367},"    \u002F\u002F (1) injectables is now a proxy\n",[362,4617,4618,4620,4622,4624,4626,4629],{"class":364,"line":427},[362,4619,2430],{"class":373},[362,4621,902],{"class":465},[362,4623,440],{"class":373},[362,4625,587],{"class":373},[362,4627,4628],{"class":436}," Proxy",[362,4630,4631],{"class":377},"(target, {\n",[362,4633,4634,4636,4638,4641,4643,4645,4647,4650],{"class":364,"line":459},[362,4635,1754],{"class":436},[362,4637,593],{"class":377},[362,4639,4640],{"class":446},"target",[362,4642,537],{"class":377},[362,4644,1527],{"class":446},[362,4646,537],{"class":377},[362,4648,4649],{"class":446},"receiver",[362,4651,1743],{"class":377},[362,4653,4654,4657,4659,4661,4664,4667],{"class":364,"line":477},[362,4655,4656],{"class":373},"        if",[362,4658,572],{"class":377},[362,4660,575],{"class":373},[362,4662,4663],{"class":377},"(prop ",[362,4665,4666],{"class":373},"in",[362,4668,4669],{"class":377}," target)) {\n",[362,4671,4672,4675,4677,4679,4681,4684,4686,4688,4691,4694,4697],{"class":364,"line":493},[362,4673,4674],{"class":373},"          throw",[362,4676,587],{"class":373},[362,4678,590],{"class":436},[362,4680,593],{"class":377},[362,4682,4683],{"class":384},"`could not resolve factory '${",[362,4685,1527],{"class":377},[362,4687,1907],{"class":384},[362,4689,4690],{"class":436},"toString",[362,4692,4693],{"class":384},"()",[362,4695,4696],{"class":384},"}'`",[362,4698,599],{"class":377},[362,4700,4701],{"class":364,"line":509},[362,4702,4703],{"class":377},"        }\n",[362,4705,4706,4708,4711,4714],{"class":364,"line":514},[362,4707,1762],{"class":373},[362,4709,4710],{"class":377}," Reflect.",[362,4712,4713],{"class":436},"get",[362,4715,4716],{"class":377},"(target, prop, receiver);\n",[362,4718,4719],{"class":364,"line":522},[362,4720,1775],{"class":377},[362,4722,4723],{"class":364,"line":546},[362,4724,4725],{"class":377},"    });\n",[362,4727,4728],{"class":364,"line":566},[362,4729,424],{"emptyLinePlaceholder":17},[362,4731,4732,4734,4736,4738,4740],{"class":364,"line":581},[362,4733,2430],{"class":373},[362,4735,1655],{"class":465},[362,4737,440],{"class":373},[362,4739,1480],{"class":436},[362,4741,1662],{"class":377},[362,4743,4744],{"class":364,"line":602},[362,4745,424],{"emptyLinePlaceholder":17},[362,4747,4748,4750,4752],{"class":364,"line":608},[362,4749,2458],{"class":377},[362,4751,1678],{"class":436},[362,4753,1681],{"class":377},[362,4755,4756],{"class":364,"line":628},[362,4757,4758],{"class":377},"      target,\n",[362,4760,4761,4763],{"class":364,"line":634},[362,4762,2472],{"class":436},[362,4764,1694],{"class":377},[362,4766,4767,4769],{"class":364,"line":640},[362,4768,2479],{"class":373},[362,4770,2482],{"class":377},[362,4772,4773,4775,4777],{"class":364,"line":1147},[362,4774,3587],{"class":377},[362,4776,2238],{"class":436},[362,4778,4779],{"class":377},"(inject),\n",[362,4781,4782,4784],{"class":364,"line":1153},[362,4783,2479],{"class":373},[362,4785,3602],{"class":377},[362,4787,4788],{"class":364,"line":1168},[362,4789,2497],{"class":377},[362,4791,4792],{"class":364,"line":1173},[362,4793,2502],{"class":377},[362,4795,4796],{"class":364,"line":1196},[362,4797,424],{"emptyLinePlaceholder":17},[362,4799,4800,4802],{"class":364,"line":1221},[362,4801,1102],{"class":373},[362,4803,1723],{"class":377},[362,4805,4806],{"class":364,"line":2039},[362,4807,424],{"emptyLinePlaceholder":17},[362,4809,4810,4812,4814,4816,4818],{"class":364,"line":2044},[362,4811,2521],{"class":373},[362,4813,1735],{"class":436},[362,4815,593],{"class":377},[362,4817,1740],{"class":446},[362,4819,1743],{"class":377},[362,4821,4822,4824,4826,4828,4830,4832,4834,4836,4838,4840,4842,4844],{"class":364,"line":2049},[362,4823,549],{"class":373},[362,4825,2536],{"class":465},[362,4827,440],{"class":373},[362,4829,2541],{"class":373},[362,4831,2544],{"class":377},[362,4833,1213],{"class":373},[362,4835,2549],{"class":384},[362,4837,2552],{"class":373},[362,4839,2544],{"class":377},[362,4841,2557],{"class":373},[362,4843,1324],{"class":436},[362,4845,4846],{"class":377},"(factory);\n",[362,4848,4849,4851],{"class":364,"line":2055},[362,4850,611],{"class":373},[362,4852,456],{"class":377},[362,4854,4855,4857],{"class":364,"line":2067},[362,4856,2576],{"class":436},[362,4858,1757],{"class":377},[362,4860,4861,4863,4865],{"class":364,"line":2073},[362,4862,2583],{"class":373},[362,4864,2536],{"class":436},[362,4866,2588],{"class":377},[362,4868,4869],{"class":364,"line":2079},[362,4870,2593],{"class":377},[362,4872,4873,4875,4877],{"class":364,"line":2085},[362,4874,2598],{"class":377},[362,4876,1783],{"class":465},[362,4878,1786],{"class":377},[362,4880,4881],{"class":364,"line":2090},[362,4882,2607],{"class":377},[362,4884,4885],{"class":364,"line":2095},[362,4886,1093],{"class":377},[362,4888,4889],{"class":364,"line":2115},[362,4890,637],{"class":377},[338,4892,4893,4894],{},"In (1) we trap all the calls to any getter to first check if the injectable has been defined. If not\nwe throw an error: the same code as above will print: ",[359,4895,4896],{},"could not resolve factory 'A'",[338,4898,4899],{},"There is a caveat though: you can’t use default values when declaring your factories. The following\ntest will not pass:",[353,4901,4903],{"className":355,"code":4902,"language":357,"meta":11,"style":11},"test(`A factory with default values should resolve to those values`, (t) => {\n  try {\n    const { a } = createInjector({\n      a: ({ b = \"foo\" }) => b,\n    });\n    t.eq(a, \"foo\", \"resolve default values\");\n  } catch (err) {\n    t.fail(\"should not have thrown\");\n  }\n});\n",[359,4904,4905,4924,4931,4947,4968,4972,4991,5001,5015,5019],{"__ignoreMap":11},[362,4906,4907,4909,4911,4914,4916,4918,4920,4922],{"class":364,"line":19},[362,4908,1176],{"class":436},[362,4910,593],{"class":377},[362,4912,4913],{"class":384},"`A factory with default values should resolve to those values`",[362,4915,1184],{"class":377},[362,4917,1187],{"class":446},[362,4919,962],{"class":377},[362,4921,453],{"class":373},[362,4923,456],{"class":377},[362,4925,4926,4929],{"class":364,"line":12},[362,4927,4928],{"class":373},"  try",[362,4930,456],{"class":377},[362,4932,4933,4935,4937,4939,4941,4943,4945],{"class":364,"line":391},[362,4934,2430],{"class":373},[362,4936,2120],{"class":377},[362,4938,1451],{"class":465},[362,4940,2126],{"class":377},[362,4942,1108],{"class":373},[362,4944,2317],{"class":436},[362,4946,1694],{"class":377},[362,4948,4949,4952,4954,4957,4959,4961,4963,4965],{"class":364,"line":406},[362,4950,4951],{"class":436},"      a",[362,4953,2712],{"class":377},[362,4955,4956],{"class":446},"b",[362,4958,440],{"class":373},[362,4960,1311],{"class":384},[362,4962,450],{"class":377},[362,4964,453],{"class":373},[362,4966,4967],{"class":377}," b,\n",[362,4969,4970],{"class":364,"line":421},[362,4971,4725],{"class":377},[362,4973,4974,4977,4979,4982,4984,4986,4989],{"class":364,"line":427},[362,4975,4976],{"class":377},"    t.",[362,4978,1416],{"class":436},[362,4980,4981],{"class":377},"(a, ",[362,4983,1427],{"class":384},[362,4985,537],{"class":377},[362,4987,4988],{"class":384},"\"resolve default values\"",[362,4990,599],{"class":377},[362,4992,4993,4996,4998],{"class":364,"line":459},[362,4994,4995],{"class":377},"  } ",[362,4997,3282],{"class":373},[362,4999,5000],{"class":377}," (err) {\n",[362,5002,5003,5005,5008,5010,5013],{"class":364,"line":477},[362,5004,4976],{"class":377},[362,5006,5007],{"class":436},"fail",[362,5009,593],{"class":377},[362,5011,5012],{"class":384},"\"should not have thrown\"",[362,5014,599],{"class":377},[362,5016,5017],{"class":364,"line":493},[362,5018,1796],{"class":377},[362,5020,5021],{"class":364,"line":509},[362,5022,1224],{"class":377},[345,5024,5026],{"id":5025},"conclusion","Conclusion",[338,5028,5029,5030,5035],{},"In this essay, we have seen what dependency injection is and how it can help to build better\nsoftware. We implemented a fairly robust and flexible DI container(injector) in a few lines of code\nthanks to the meta-programming features of Javascript. This component does not depend on any\nframework. You can see an example of a web server (based on Fastify) using this DI component in this\n",[1451,5031,5034],{"href":5032,"rel":5033},"https:\u002F\u002Fgithub.com\u002Florenzofox3\u002Fdi-example",[1455],"repository",". Details are given in the readme.",[5037,5038,5039],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":11,"searchDepth":12,"depth":12,"links":5041},[5042,5043,5044,5045,5046,5047,5048,5049],{"id":347,"depth":12,"text":348},{"id":817,"depth":12,"text":818},{"id":933,"depth":12,"text":934},{"id":1442,"depth":12,"text":1443},{"id":2359,"depth":12,"text":2360},{"id":3012,"depth":12,"text":3013},{"id":4478,"depth":12,"text":4479},{"id":5025,"depth":12,"text":5026},"2022-07-21","Dependency Injection (DI) is a technique in which a software component receives other components (its dependencies) without it to have the responsibility to...","en",{},"\u002Farticles\u002F2022-07-21-lets-build-a-di-system-in-javascript-using-meta-programming",{"title":333,"description":5051},"articles\u002F2022-07-21-lets-build-a-di-system-in-javascript-using-meta-programming",[5058],"Tech","G6SmiryV9odR_Ozg6Q5l3QG5FHozHntgx7aJFYuOUng",1778159243243]