You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

jsv.js 113KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700
  1. // This is a build of https://github.com/garycourt/JSV at 0aa11852537069b0830569ef1eab11a36b65b3ab with jsv.js, schema03 and URI.js appended.
  2. // The build contains a few lines of custom code to handle format validation.
  3. // Custom code is wrapped in comments that start with "JOSHFIRE"
  4. (function(global, require) {
  5. var exports = {};
  6. /**
  7. * URI.js
  8. *
  9. * @fileoverview An RFC 3986 compliant, scheme extendable URI parsing/validating/resolving library for JavaScript.
  10. * @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
  11. * @version 1.2
  12. * @see http://github.com/garycourt/uri-js
  13. * @license URI.js v1.2 (c) 2010 Gary Court. License: http://github.com/garycourt/uri-js
  14. */
  15. /**
  16. * Copyright 2010 Gary Court. All rights reserved.
  17. *
  18. * Redistribution and use in source and binary forms, with or without modification, are
  19. * permitted provided that the following conditions are met:
  20. *
  21. * 1. Redistributions of source code must retain the above copyright notice, this list of
  22. * conditions and the following disclaimer.
  23. *
  24. * 2. Redistributions in binary form must reproduce the above copyright notice, this list
  25. * of conditions and the following disclaimer in the documentation and/or other materials
  26. * provided with the distribution.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
  29. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  30. * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
  31. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  33. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  34. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  36. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * The views and conclusions contained in the software and documentation are those of the
  39. * authors and should not be interpreted as representing official policies, either expressed
  40. * or implied, of Gary Court.
  41. */
  42. /*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
  43. /*global exports:true, require:true */
  44. if (typeof exports === "undefined") {
  45. exports = {};
  46. }
  47. if (typeof require !== "function") {
  48. require = function (id) {
  49. return exports;
  50. };
  51. }
  52. (function () {
  53. var
  54. /**
  55. * @param {...string} sets
  56. * @return {string}
  57. */
  58. mergeSet = function (sets) {
  59. var set = arguments[0],
  60. x = 1,
  61. nextSet = arguments[x];
  62. while (nextSet) {
  63. set = set.slice(0, -1) + nextSet.slice(1);
  64. nextSet = arguments[++x];
  65. }
  66. return set;
  67. },
  68. /**
  69. * @param {string} str
  70. * @return {string}
  71. */
  72. subexp = function (str) {
  73. return "(?:" + str + ")";
  74. },
  75. ALPHA$$ = "[A-Za-z]",
  76. CR$ = "[\\x0D]",
  77. DIGIT$$ = "[0-9]",
  78. DQUOTE$$ = "[\\x22]",
  79. HEXDIG$$ = mergeSet(DIGIT$$, "[A-Fa-f]"), //case-insensitive
  80. LF$$ = "[\\x0A]",
  81. SP$$ = "[\\x20]",
  82. PCT_ENCODED$ = subexp("%" + HEXDIG$$ + HEXDIG$$),
  83. GEN_DELIMS$$ = "[\\:\\/\\?\\#\\[\\]\\@]",
  84. SUB_DELIMS$$ = "[\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=]",
  85. RESERVED$$ = mergeSet(GEN_DELIMS$$, SUB_DELIMS$$),
  86. UNRESERVED$$ = mergeSet(ALPHA$$, DIGIT$$, "[\\-\\.\\_\\~]"),
  87. SCHEME$ = subexp(ALPHA$$ + mergeSet(ALPHA$$, DIGIT$$, "[\\+\\-\\.]") + "*"),
  88. USERINFO$ = subexp(subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:]")) + "*"),
  89. DEC_OCTET$ = subexp(subexp("25[0-5]") + "|" + subexp("2[0-4]" + DIGIT$$) + "|" + subexp("1" + DIGIT$$ + DIGIT$$) + "|" + subexp("[1-9]" + DIGIT$$) + "|" + DIGIT$$),
  90. IPV4ADDRESS$ = subexp(DEC_OCTET$ + "\\." + DEC_OCTET$ + "\\." + DEC_OCTET$ + "\\." + DEC_OCTET$),
  91. H16$ = subexp(HEXDIG$$ + "{1,4}"),
  92. LS32$ = subexp(subexp(H16$ + "\\:" + H16$) + "|" + IPV4ADDRESS$),
  93. IPV6ADDRESS$ = subexp(mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:]") + "+"), //FIXME
  94. IPVFUTURE$ = subexp("v" + HEXDIG$$ + "+\\." + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:]") + "+"),
  95. IP_LITERAL$ = subexp("\\[" + subexp(IPV6ADDRESS$ + "|" + IPVFUTURE$) + "\\]"),
  96. REG_NAME$ = subexp(subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$)) + "*"),
  97. HOST$ = subexp(IP_LITERAL$ + "|" + IPV4ADDRESS$ + "|" + REG_NAME$),
  98. PORT$ = subexp(DIGIT$$ + "*"),
  99. AUTHORITY$ = subexp(subexp(USERINFO$ + "@") + "?" + HOST$ + subexp("\\:" + PORT$) + "?"),
  100. PCHAR$ = subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@]")),
  101. SEGMENT$ = subexp(PCHAR$ + "*"),
  102. SEGMENT_NZ$ = subexp(PCHAR$ + "+"),
  103. SEGMENT_NZ_NC$ = subexp(subexp(PCT_ENCODED$ + "|" + mergeSet(UNRESERVED$$, SUB_DELIMS$$, "[\\@]")) + "+"),
  104. PATH_ABEMPTY$ = subexp(subexp("\\/" + SEGMENT$) + "*"),
  105. PATH_ABSOLUTE$ = subexp("\\/" + subexp(SEGMENT_NZ$ + PATH_ABEMPTY$) + "?"), //simplified
  106. PATH_NOSCHEME$ = subexp(SEGMENT_NZ_NC$ + PATH_ABEMPTY$), //simplified
  107. PATH_ROOTLESS$ = subexp(SEGMENT_NZ$ + PATH_ABEMPTY$), //simplified
  108. PATH_EMPTY$ = subexp(""), //simplified
  109. PATH$ = subexp(PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$),
  110. QUERY$ = subexp(subexp(PCHAR$ + "|[\\/\\?]") + "*"),
  111. FRAGMENT$ = subexp(subexp(PCHAR$ + "|[\\/\\?]") + "*"),
  112. HIER_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$),
  113. URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"),
  114. RELATIVE_PART$ = subexp(subexp("\\/\\/" + AUTHORITY$ + PATH_ABEMPTY$) + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$),
  115. RELATIVE_REF$ = subexp(RELATIVE_PART$ + subexp("\\?" + QUERY$) + "?" + subexp("\\#" + FRAGMENT$) + "?"),
  116. URI_REFERENCE$ = subexp(URI$ + "|" + RELATIVE_REF$),
  117. ABSOLUTE_URI$ = subexp(SCHEME$ + "\\:" + HIER_PART$ + subexp("\\?" + QUERY$) + "?"),
  118. URI_REF = new RegExp("^" + subexp("(" + URI$ + ")|(" + RELATIVE_REF$ + ")") + "$"),
  119. GENERIC_REF = new RegExp("^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$"),
  120. RELATIVE_REF = new RegExp("^(){0}" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_NOSCHEME$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?" + subexp("\\#(" + FRAGMENT$ + ")") + "?$"),
  121. ABSOLUTE_REF = new RegExp("^(" + SCHEME$ + ")\\:" + subexp(subexp("\\/\\/(" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?)") + "?(" + PATH_ABEMPTY$ + "|" + PATH_ABSOLUTE$ + "|" + PATH_ROOTLESS$ + "|" + PATH_EMPTY$ + ")") + subexp("\\?(" + QUERY$ + ")") + "?$"),
  122. SAMEDOC_REF = new RegExp("^" + subexp("\\#(" + FRAGMENT$ + ")") + "?$"),
  123. AUTHORITY = new RegExp("^" + subexp("(" + USERINFO$ + ")@") + "?(" + HOST$ + ")" + subexp("\\:(" + PORT$ + ")") + "?$"),
  124. NOT_SCHEME = new RegExp(mergeSet("[^]", ALPHA$$, DIGIT$$, "[\\+\\-\\.]"), "g"),
  125. NOT_USERINFO = new RegExp(mergeSet("[^\\%\\:]", UNRESERVED$$, SUB_DELIMS$$), "g"),
  126. NOT_HOST = new RegExp(mergeSet("[^\\%]", UNRESERVED$$, SUB_DELIMS$$), "g"),
  127. NOT_PATH = new RegExp(mergeSet("[^\\%\\/\\:\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"),
  128. NOT_PATH_NOSCHEME = new RegExp(mergeSet("[^\\%\\/\\@]", UNRESERVED$$, SUB_DELIMS$$), "g"),
  129. NOT_QUERY = new RegExp(mergeSet("[^\\%]", UNRESERVED$$, SUB_DELIMS$$, "[\\:\\@\\/\\?]"), "g"),
  130. NOT_FRAGMENT = NOT_QUERY,
  131. ESCAPE = new RegExp(mergeSet("[^]", UNRESERVED$$, SUB_DELIMS$$), "g"),
  132. UNRESERVED = new RegExp(UNRESERVED$$, "g"),
  133. OTHER_CHARS = new RegExp(mergeSet("[^\\%]", UNRESERVED$$, RESERVED$$), "g"),
  134. PCT_ENCODEDS = new RegExp(PCT_ENCODED$ + "+", "g"),
  135. URI_PARSE = /^(?:([^:\/?#]+):)?(?:\/\/((?:([^\/?#@]*)@)?([^\/?#:]*)(?:\:(\d*))?))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/i,
  136. RDS1 = /^\.\.?\//,
  137. RDS2 = /^\/\.(\/|$)/,
  138. RDS3 = /^\/\.\.(\/|$)/,
  139. RDS4 = /^\.\.?$/,
  140. RDS5 = /^\/?.*?(?=\/|$)/,
  141. NO_MATCH_IS_UNDEFINED = ("").match(/(){0}/)[1] === undefined,
  142. /**
  143. * @param {string} chr
  144. * @return {string}
  145. */
  146. pctEncChar = function (chr) {
  147. var c = chr.charCodeAt(0);
  148. if (c < 128) {
  149. return "%" + c.toString(16).toUpperCase();
  150. }
  151. else if ((c > 127) && (c < 2048)) {
  152. return "%" + ((c >> 6) | 192).toString(16).toUpperCase() + "%" + ((c & 63) | 128).toString(16).toUpperCase();
  153. }
  154. else {
  155. return "%" + ((c >> 12) | 224).toString(16).toUpperCase() + "%" + (((c >> 6) & 63) | 128).toString(16).toUpperCase() + "%" + ((c & 63) | 128).toString(16).toUpperCase();
  156. }
  157. },
  158. /**
  159. * @param {string} str
  160. * @return {string}
  161. */
  162. pctDecUnreserved = function (str) {
  163. var newStr = "",
  164. i = 0,
  165. c, s;
  166. while (i < str.length) {
  167. c = parseInt(str.substr(i + 1, 2), 16);
  168. if (c < 128) {
  169. s = String.fromCharCode(c);
  170. if (s.match(UNRESERVED)) {
  171. newStr += s;
  172. } else {
  173. newStr += str.substr(i, 3);
  174. }
  175. i += 3;
  176. }
  177. else if ((c > 191) && (c < 224)) {
  178. newStr += str.substr(i, 6);
  179. i += 6;
  180. }
  181. else {
  182. newStr += str.substr(i, 9);
  183. i += 9;
  184. }
  185. }
  186. return newStr;
  187. },
  188. /**
  189. * @param {string} str
  190. * @return {string}
  191. */
  192. pctDecChars = function (str) {
  193. var newStr = "",
  194. i = 0,
  195. c, c2, c3;
  196. while (i < str.length) {
  197. c = parseInt(str.substr(i + 1, 2), 16);
  198. if (c < 128) {
  199. newStr += String.fromCharCode(c);
  200. i += 3;
  201. }
  202. else if ((c > 191) && (c < 224)) {
  203. c2 = parseInt(str.substr(i + 4, 2), 16);
  204. newStr += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  205. i += 6;
  206. }
  207. else {
  208. c2 = parseInt(str.substr(i + 4, 2), 16);
  209. c3 = parseInt(str.substr(i + 7, 2), 16);
  210. newStr += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  211. i += 9;
  212. }
  213. }
  214. return newStr;
  215. },
  216. /**
  217. * @return {string}
  218. */
  219. typeOf = function (o) {
  220. return o === undefined ? "undefined" : (o === null ? "null" : Object.prototype.toString.call(o).split(" ").pop().split("]").shift().toLowerCase());
  221. },
  222. /**
  223. * @constructor
  224. * @implements URIComponents
  225. */
  226. Components = function () {
  227. this.errors = [];
  228. },
  229. /** @namespace */
  230. URI = {};
  231. /**
  232. * Components
  233. */
  234. Components.prototype = {
  235. /**
  236. * @type String
  237. */
  238. scheme : undefined,
  239. /**
  240. * @type String
  241. */
  242. authority : undefined,
  243. /**
  244. * @type String
  245. */
  246. userinfo : undefined,
  247. /**
  248. * @type String
  249. */
  250. host : undefined,
  251. /**
  252. * @type number
  253. */
  254. port : undefined,
  255. /**
  256. * @type string
  257. */
  258. path : undefined,
  259. /**
  260. * @type string
  261. */
  262. query : undefined,
  263. /**
  264. * @type string
  265. */
  266. fragment : undefined,
  267. /**
  268. * @type string
  269. * @values "uri", "absolute", "relative", "same-document"
  270. */
  271. reference : undefined,
  272. /**
  273. * @type Array
  274. */
  275. errors : undefined
  276. };
  277. /**
  278. * URI
  279. */
  280. /**
  281. * @namespace
  282. */
  283. URI.SCHEMES = {};
  284. /**
  285. * @param {string} uriString
  286. * @param {Options} [options]
  287. * @returns {URIComponents}
  288. */
  289. URI.parse = function (uriString, options) {
  290. var matches,
  291. components = new Components(),
  292. schemeHandler;
  293. uriString = uriString ? uriString.toString() : "";
  294. options = options || {};
  295. if (options.reference === "suffix") {
  296. uriString = (options.scheme ? options.scheme + ":" : "") + "//" + uriString;
  297. }
  298. matches = uriString.match(URI_REF);
  299. if (matches) {
  300. if (matches[1]) {
  301. //generic URI
  302. matches = uriString.match(GENERIC_REF);
  303. } else {
  304. //relative URI
  305. matches = uriString.match(RELATIVE_REF);
  306. }
  307. }
  308. if (!matches) {
  309. if (!options.tolerant) {
  310. components.errors.push("URI is not strictly valid.");
  311. }
  312. matches = uriString.match(URI_PARSE);
  313. }
  314. if (matches) {
  315. if (NO_MATCH_IS_UNDEFINED) {
  316. //store each component
  317. components.scheme = matches[1];
  318. components.authority = matches[2];
  319. components.userinfo = matches[3];
  320. components.host = matches[4];
  321. components.port = parseInt(matches[5], 10);
  322. components.path = matches[6] || "";
  323. components.query = matches[7];
  324. components.fragment = matches[8];
  325. //fix port number
  326. if (isNaN(components.port)) {
  327. components.port = matches[5];
  328. }
  329. } else { //IE FIX for improper RegExp matching
  330. //store each component
  331. components.scheme = matches[1] || undefined;
  332. components.authority = (uriString.indexOf("//") !== -1 ? matches[2] : undefined);
  333. components.userinfo = (uriString.indexOf("@") !== -1 ? matches[3] : undefined);
  334. components.host = (uriString.indexOf("//") !== -1 ? matches[4] : undefined);
  335. components.port = parseInt(matches[5], 10);
  336. components.path = matches[6] || "";
  337. components.query = (uriString.indexOf("?") !== -1 ? matches[7] : undefined);
  338. components.fragment = (uriString.indexOf("#") !== -1 ? matches[8] : undefined);
  339. //fix port number
  340. if (isNaN(components.port)) {
  341. components.port = (uriString.match(/\/\/.*\:(?:\/|\?|\#|$)/) ? matches[4] : undefined);
  342. }
  343. }
  344. //determine reference type
  345. if (!components.scheme && !components.authority && !components.path && !components.query) {
  346. components.reference = "same-document";
  347. } else if (!components.scheme) {
  348. components.reference = "relative";
  349. } else if (!components.fragment) {
  350. components.reference = "absolute";
  351. } else {
  352. components.reference = "uri";
  353. }
  354. //check for reference errors
  355. if (options.reference && options.reference !== "suffix" && options.reference !== components.reference) {
  356. components.errors.push("URI is not a " + options.reference + " reference.");
  357. }
  358. //check if a handler for the scheme exists
  359. schemeHandler = URI.SCHEMES[components.scheme || options.scheme];
  360. if (schemeHandler && schemeHandler.parse) {
  361. //perform extra parsing
  362. schemeHandler.parse(components, options);
  363. }
  364. } else {
  365. components.errors.push("URI can not be parsed.");
  366. }
  367. return components;
  368. };
  369. /**
  370. * @private
  371. * @param {URIComponents} components
  372. * @returns {string|undefined}
  373. */
  374. URI._recomposeAuthority = function (components) {
  375. var uriTokens = [];
  376. if (components.userinfo !== undefined || components.host !== undefined || typeof components.port === "number") {
  377. if (components.userinfo !== undefined) {
  378. uriTokens.push(components.userinfo.toString().replace(NOT_USERINFO, pctEncChar));
  379. uriTokens.push("@");
  380. }
  381. if (components.host !== undefined) {
  382. uriTokens.push(components.host.toString().toLowerCase().replace(NOT_HOST, pctEncChar));
  383. }
  384. if (typeof components.port === "number") {
  385. uriTokens.push(":");
  386. uriTokens.push(components.port.toString(10));
  387. }
  388. }
  389. return uriTokens.length ? uriTokens.join("") : undefined;
  390. };
  391. /**
  392. * @param {string} input
  393. * @returns {string}
  394. */
  395. URI.removeDotSegments = function (input) {
  396. var output = [], s;
  397. while (input.length) {
  398. if (input.match(RDS1)) {
  399. input = input.replace(RDS1, "");
  400. } else if (input.match(RDS2)) {
  401. input = input.replace(RDS2, "/");
  402. } else if (input.match(RDS3)) {
  403. input = input.replace(RDS3, "/");
  404. output.pop();
  405. } else if (input === "." || input === "..") {
  406. input = "";
  407. } else {
  408. s = input.match(RDS5)[0];
  409. input = input.slice(s.length);
  410. output.push(s);
  411. }
  412. }
  413. return output.join("");
  414. };
  415. /**
  416. * @param {URIComponents} components
  417. * @param {Options} [options]
  418. * @returns {string}
  419. */
  420. URI.serialize = function (components, options) {
  421. var uriTokens = [],
  422. schemeHandler,
  423. s;
  424. options = options || {};
  425. //check if a handler for the scheme exists
  426. schemeHandler = URI.SCHEMES[components.scheme || options.scheme];
  427. if (schemeHandler && schemeHandler.serialize) {
  428. //perform extra serialization
  429. schemeHandler.serialize(components, options);
  430. }
  431. if (options.reference !== "suffix" && components.scheme) {
  432. uriTokens.push(components.scheme.toString().toLowerCase().replace(NOT_SCHEME, ""));
  433. uriTokens.push(":");
  434. }
  435. components.authority = URI._recomposeAuthority(components);
  436. if (components.authority !== undefined) {
  437. if (options.reference !== "suffix") {
  438. uriTokens.push("//");
  439. }
  440. uriTokens.push(components.authority);
  441. if (components.path && components.path.charAt(0) !== "/") {
  442. uriTokens.push("/");
  443. }
  444. }
  445. if (components.path) {
  446. s = URI.removeDotSegments(components.path.toString().replace(/%2E/ig, "."));
  447. if (components.scheme) {
  448. s = s.replace(NOT_PATH, pctEncChar);
  449. } else {
  450. s = s.replace(NOT_PATH_NOSCHEME, pctEncChar);
  451. }
  452. if (components.authority === undefined) {
  453. s = s.replace(/^\/\//, "/%2F"); //don't allow the path to start with "//"
  454. }
  455. uriTokens.push(s);
  456. }
  457. if (components.query) {
  458. uriTokens.push("?");
  459. uriTokens.push(components.query.toString().replace(NOT_QUERY, pctEncChar));
  460. }
  461. if (components.fragment) {
  462. uriTokens.push("#");
  463. uriTokens.push(components.fragment.toString().replace(NOT_FRAGMENT, pctEncChar));
  464. }
  465. return uriTokens
  466. .join('') //merge tokens into a string
  467. .replace(PCT_ENCODEDS, pctDecUnreserved) //undecode unreserved characters
  468. //.replace(OTHER_CHARS, pctEncChar) //replace non-URI characters
  469. .replace(/%[0-9A-Fa-f]{2}/g, function (str) { //uppercase percent encoded characters
  470. return str.toUpperCase();
  471. })
  472. ;
  473. };
  474. /**
  475. * @param {URIComponents} base
  476. * @param {URIComponents} relative
  477. * @param {Options} [options]
  478. * @param {boolean} [skipNormalization]
  479. * @returns {URIComponents}
  480. */
  481. URI.resolveComponents = function (base, relative, options, skipNormalization) {
  482. var target = new Components();
  483. if (!skipNormalization) {
  484. base = URI.parse(URI.serialize(base, options), options); //normalize base components
  485. relative = URI.parse(URI.serialize(relative, options), options); //normalize relative components
  486. }
  487. options = options || {};
  488. if (!options.tolerant && relative.scheme) {
  489. target.scheme = relative.scheme;
  490. target.authority = relative.authority;
  491. target.userinfo = relative.userinfo;
  492. target.host = relative.host;
  493. target.port = relative.port;
  494. target.path = URI.removeDotSegments(relative.path);
  495. target.query = relative.query;
  496. } else {
  497. if (relative.authority !== undefined) {
  498. target.authority = relative.authority;
  499. target.userinfo = relative.userinfo;
  500. target.host = relative.host;
  501. target.port = relative.port;
  502. target.path = URI.removeDotSegments(relative.path);
  503. target.query = relative.query;
  504. } else {
  505. if (!relative.path) {
  506. target.path = base.path;
  507. if (relative.query !== undefined) {
  508. target.query = relative.query;
  509. } else {
  510. target.query = base.query;
  511. }
  512. } else {
  513. if (relative.path.charAt(0) === "/") {
  514. target.path = URI.removeDotSegments(relative.path);
  515. } else {
  516. if (base.authority !== undefined && !base.path) {
  517. target.path = "/" + relative.path;
  518. } else if (!base.path) {
  519. target.path = relative.path;
  520. } else {
  521. target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
  522. }
  523. target.path = URI.removeDotSegments(target.path);
  524. }
  525. target.query = relative.query;
  526. }
  527. target.authority = base.authority;
  528. target.userinfo = base.userinfo;
  529. target.host = base.host;
  530. target.port = base.port;
  531. }
  532. target.scheme = base.scheme;
  533. }
  534. target.fragment = relative.fragment;
  535. return target;
  536. };
  537. /**
  538. * @param {string} baseURI
  539. * @param {string} relativeURI
  540. * @param {Options} [options]
  541. * @returns {string}
  542. */
  543. URI.resolve = function (baseURI, relativeURI, options) {
  544. return URI.serialize(URI.resolveComponents(URI.parse(baseURI, options), URI.parse(relativeURI, options), options, true), options);
  545. };
  546. /**
  547. * @param {string|URIComponents} uri
  548. * @param {Options} options
  549. * @returns {string|URIComponents}
  550. */
  551. URI.normalize = function (uri, options) {
  552. if (typeof uri === "string") {
  553. return URI.serialize(URI.parse(uri, options), options);
  554. } else if (typeOf(uri) === "object") {
  555. return URI.parse(URI.serialize(uri, options), options);
  556. }
  557. return uri;
  558. };
  559. /**
  560. * @param {string|URIComponents} uriA
  561. * @param {string|URIComponents} uriB
  562. * @param {Options} options
  563. */
  564. URI.equal = function (uriA, uriB, options) {
  565. if (typeof uriA === "string") {
  566. uriA = URI.serialize(URI.parse(uriA, options), options);
  567. } else if (typeOf(uriA) === "object") {
  568. uriA = URI.serialize(uriA, options);
  569. }
  570. if (typeof uriB === "string") {
  571. uriB = URI.serialize(URI.parse(uriB, options), options);
  572. } else if (typeOf(uriB) === "object") {
  573. uriB = URI.serialize(uriB, options);
  574. }
  575. return uriA === uriB;
  576. };
  577. /**
  578. * @param {string} str
  579. * @returns {string}
  580. */
  581. URI.escapeComponent = function (str) {
  582. return str && str.toString().replace(ESCAPE, pctEncChar);
  583. };
  584. /**
  585. * @param {string} str
  586. * @returns {string}
  587. */
  588. URI.unescapeComponent = function (str) {
  589. return str && str.toString().replace(PCT_ENCODEDS, pctDecChars);
  590. };
  591. //export API
  592. exports.Components = Components;
  593. exports.URI = URI;
  594. //name-safe export API
  595. exports["URI"] = {
  596. "SCHEMES" : URI.SCHEMES,
  597. "parse" : URI.parse,
  598. "removeDotSegments" : URI.removeDotSegments,
  599. "serialize" : URI.serialize,
  600. "resolveComponents" : URI.resolveComponents,
  601. "resolve" : URI.resolve,
  602. "normalize" : URI.normalize,
  603. "equal" : URI.equal,
  604. "escapeComponent" : URI.escapeComponent,
  605. "unescapeComponent" : URI.unescapeComponent
  606. };
  607. }());
  608. /**
  609. * JSV: JSON Schema Validator
  610. *
  611. * @fileOverview A JavaScript implementation of a extendable, fully compliant JSON Schema validator.
  612. * @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
  613. * @version 3.5
  614. * @see http://github.com/garycourt/JSV
  615. */
  616. /*
  617. * Copyright 2010 Gary Court. All rights reserved.
  618. *
  619. * Redistribution and use in source and binary forms, with or without modification, are
  620. * permitted provided that the following conditions are met:
  621. *
  622. * 1. Redistributions of source code must retain the above copyright notice, this list of
  623. * conditions and the following disclaimer.
  624. *
  625. * 2. Redistributions in binary form must reproduce the above copyright notice, this list
  626. * of conditions and the following disclaimer in the documentation and/or other materials
  627. * provided with the distribution.
  628. *
  629. * THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
  630. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  631. * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
  632. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  633. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  634. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  635. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  636. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  637. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  638. *
  639. * The views and conclusions contained in the software and documentation are those of the
  640. * authors and should not be interpreted as representing official policies, either expressed
  641. * or implied, of Gary Court or the JSON Schema specification.
  642. */
  643. /*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
  644. var exports = exports || this,
  645. require = require || function () {
  646. return exports;
  647. };
  648. (function () {
  649. var URI = require("./uri/uri").URI,
  650. O = {},
  651. I2H = "0123456789abcdef".split(""),
  652. mapArray, filterArray, searchArray,
  653. JSV;
  654. //
  655. // Utility functions
  656. //
  657. function typeOf(o) {
  658. return o === undefined ? "undefined" : (o === null ? "null" : Object.prototype.toString.call(o).split(" ").pop().split("]").shift().toLowerCase());
  659. }
  660. /** @inner */
  661. function F() {}
  662. function createObject(proto) {
  663. F.prototype = proto || {};
  664. return new F();
  665. }
  666. function mapObject(obj, func, scope) {
  667. var newObj = {}, key;
  668. for (key in obj) {
  669. if (obj[key] !== O[key]) {
  670. newObj[key] = func.call(scope, obj[key], key, obj);
  671. }
  672. }
  673. return newObj;
  674. }
  675. /** @ignore */
  676. mapArray = function (arr, func, scope) {
  677. var x = 0, xl = arr.length, newArr = new Array(xl);
  678. for (; x < xl; ++x) {
  679. newArr[x] = func.call(scope, arr[x], x, arr);
  680. }
  681. return newArr;
  682. };
  683. if (Array.prototype.map) {
  684. /** @ignore */
  685. mapArray = function (arr, func, scope) {
  686. return Array.prototype.map.call(arr, func, scope);
  687. };
  688. }
  689. /** @ignore */
  690. filterArray = function (arr, func, scope) {
  691. var x = 0, xl = arr.length, newArr = [];
  692. for (; x < xl; ++x) {
  693. if (func.call(scope, arr[x], x, arr)) {
  694. newArr[newArr.length] = arr[x];
  695. }
  696. }
  697. return newArr;
  698. };
  699. if (Array.prototype.filter) {
  700. /** @ignore */
  701. filterArray = function (arr, func, scope) {
  702. return Array.prototype.filter.call(arr, func, scope);
  703. };
  704. }
  705. /** @ignore */
  706. searchArray = function (arr, o) {
  707. var x = 0, xl = arr.length;
  708. for (; x < xl; ++x) {
  709. if (arr[x] === o) {
  710. return x;
  711. }
  712. }
  713. return -1;
  714. };
  715. if (Array.prototype.indexOf) {
  716. /** @ignore */
  717. searchArray = function (arr, o) {
  718. return Array.prototype.indexOf.call(arr, o);
  719. };
  720. }
  721. function toArray(o) {
  722. return o !== undefined && o !== null ? (o instanceof Array && !o.callee ? o : (typeof o.length !== "number" || o.split || o.setInterval || o.call ? [ o ] : Array.prototype.slice.call(o))) : [];
  723. }
  724. function keys(o) {
  725. var result = [], key;
  726. switch (typeOf(o)) {
  727. case "object":
  728. for (key in o) {
  729. if (o[key] !== O[key]) {
  730. result[result.length] = key;
  731. }
  732. }
  733. break;
  734. case "array":
  735. for (key = o.length - 1; key >= 0; --key) {
  736. result[key] = key;
  737. }
  738. break;
  739. }
  740. return result;
  741. }
  742. function pushUnique(arr, o) {
  743. if (searchArray(arr, o) === -1) {
  744. arr.push(o);
  745. }
  746. return arr;
  747. }
  748. function popFirst(arr, o) {
  749. var index = searchArray(arr, o);
  750. if (index > -1) {
  751. arr.splice(index, 1);
  752. }
  753. return arr;
  754. }
  755. function randomUUID() {
  756. return [
  757. I2H[Math.floor(Math.random() * 0x10)],
  758. I2H[Math.floor(Math.random() * 0x10)],
  759. I2H[Math.floor(Math.random() * 0x10)],
  760. I2H[Math.floor(Math.random() * 0x10)],
  761. I2H[Math.floor(Math.random() * 0x10)],
  762. I2H[Math.floor(Math.random() * 0x10)],
  763. I2H[Math.floor(Math.random() * 0x10)],
  764. I2H[Math.floor(Math.random() * 0x10)],
  765. "-",
  766. I2H[Math.floor(Math.random() * 0x10)],
  767. I2H[Math.floor(Math.random() * 0x10)],
  768. I2H[Math.floor(Math.random() * 0x10)],
  769. I2H[Math.floor(Math.random() * 0x10)],
  770. "-4", //set 4 high bits of time_high field to version
  771. I2H[Math.floor(Math.random() * 0x10)],
  772. I2H[Math.floor(Math.random() * 0x10)],
  773. I2H[Math.floor(Math.random() * 0x10)],
  774. "-",
  775. I2H[(Math.floor(Math.random() * 0x10) & 0x3) | 0x8], //specify 2 high bits of clock sequence
  776. I2H[Math.floor(Math.random() * 0x10)],
  777. I2H[Math.floor(Math.random() * 0x10)],
  778. I2H[Math.floor(Math.random() * 0x10)],
  779. "-",
  780. I2H[Math.floor(Math.random() * 0x10)],
  781. I2H[Math.floor(Math.random() * 0x10)],
  782. I2H[Math.floor(Math.random() * 0x10)],
  783. I2H[Math.floor(Math.random() * 0x10)],
  784. I2H[Math.floor(Math.random() * 0x10)],
  785. I2H[Math.floor(Math.random() * 0x10)],
  786. I2H[Math.floor(Math.random() * 0x10)],
  787. I2H[Math.floor(Math.random() * 0x10)],
  788. I2H[Math.floor(Math.random() * 0x10)],
  789. I2H[Math.floor(Math.random() * 0x10)],
  790. I2H[Math.floor(Math.random() * 0x10)],
  791. I2H[Math.floor(Math.random() * 0x10)]
  792. ].join("");
  793. }
  794. function escapeURIComponent(str) {
  795. return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A');
  796. }
  797. function formatURI(uri) {
  798. if (typeof uri === "string" && uri.indexOf("#") === -1) {
  799. uri += "#";
  800. }
  801. return uri;
  802. }
  803. /**
  804. * Defines an error, found by a schema, with an instance.
  805. * This class can only be instantiated by {@link Report#addError}.
  806. *
  807. * @name ValidationError
  808. * @class
  809. * @see Report#addError
  810. */
  811. /**
  812. * The URI of the instance that has the error.
  813. *
  814. * @name ValidationError.prototype.uri
  815. * @type String
  816. */
  817. /**
  818. * The URI of the schema that generated the error.
  819. *
  820. * @name ValidationError.prototype.schemaUri
  821. * @type String
  822. */
  823. /**
  824. * The name of the schema attribute that generated the error.
  825. *
  826. * @name ValidationError.prototype.attribute
  827. * @type String
  828. */
  829. /**
  830. * An user-friendly (English) message about what failed to validate.
  831. *
  832. * @name ValidationError.prototype.message
  833. * @type String
  834. */
  835. /**
  836. * The value of the schema attribute that generated the error.
  837. *
  838. * @name ValidationError.prototype.details
  839. * @type Any
  840. */
  841. /**
  842. * Reports are returned from validation methods to describe the result of a validation.
  843. *
  844. * @name Report
  845. * @class
  846. * @see JSONSchema#validate
  847. * @see Environment#validate
  848. */
  849. function Report() {
  850. /**
  851. * An array of {@link ValidationError} objects that define all the errors generated by the schema against the instance.
  852. *
  853. * @name Report.prototype.errors
  854. * @type Array
  855. * @see Report#addError
  856. */
  857. this.errors = [];
  858. /**
  859. * A hash table of every instance and what schemas were validated against it.
  860. * <p>
  861. * The key of each item in the table is the URI of the instance that was validated.
  862. * The value of this key is an array of strings of URIs of the schema that validated it.
  863. * </p>
  864. *
  865. * @name Report.prototype.validated
  866. * @type Object
  867. * @see Report#registerValidation
  868. * @see Report#isValidatedBy
  869. */
  870. this.validated = {};
  871. /**
  872. * If the report is generated by {@link Environment#validate}, this field is the generated instance.
  873. *
  874. * @name Report.prototype.instance
  875. * @type JSONInstance
  876. * @see Environment#validate
  877. */
  878. /**
  879. * If the report is generated by {@link Environment#validate}, this field is the generated schema.
  880. *
  881. * @name Report.prototype.schema
  882. * @type JSONSchema
  883. * @see Environment#validate
  884. */
  885. /**
  886. * If the report is generated by {@link Environment#validate}, this field is the schema's schema.
  887. * This value is the same as calling <code>schema.getSchema()</code>.
  888. *
  889. * @name Report.prototype.schemaSchema
  890. * @type JSONSchema
  891. * @see Environment#validate
  892. * @see JSONSchema#getSchema
  893. */
  894. }
  895. /**
  896. * Adds a {@link ValidationError} object to the <a href="#errors"><code>errors</code></a> field.
  897. *
  898. * @param {JSONInstance|String} instance The instance (or instance URI) that is invalid
  899. * @param {JSONSchema|String} schema The schema (or schema URI) that was validating the instance
  900. * @param {String} attr The attribute that failed to validated
  901. * @param {String} message A user-friendly message on why the schema attribute failed to validate the instance
  902. * @param {Any} details The value of the schema attribute
  903. */
  904. Report.prototype.addError = function (instance, schema, attr, message, details) {
  905. this.errors.push({
  906. uri : instance instanceof JSONInstance ? instance.getURI() : instance,
  907. schemaUri : schema instanceof JSONInstance ? schema.getURI() : schema,
  908. attribute : attr,
  909. message : message,
  910. details : details
  911. });
  912. };
  913. /**
  914. * Registers that the provided instance URI has been validated by the provided schema URI.
  915. * This is recorded in the <a href="#validated"><code>validated</code></a> field.
  916. *
  917. * @param {String} uri The URI of the instance that was validated
  918. * @param {String} schemaUri The URI of the schema that validated the instance
  919. */
  920. Report.prototype.registerValidation = function (uri, schemaUri) {
  921. if (!this.validated[uri]) {
  922. this.validated[uri] = [ schemaUri ];
  923. } else {
  924. this.validated[uri].push(schemaUri);
  925. }
  926. };
  927. /**
  928. * Returns if an instance with the provided URI has been validated by the schema with the provided URI.
  929. *
  930. * @param {String} uri The URI of the instance
  931. * @param {String} schemaUri The URI of a schema
  932. * @returns {Boolean} If the instance has been validated by the schema.
  933. */
  934. Report.prototype.isValidatedBy = function (uri, schemaUri) {
  935. return !!this.validated[uri] && searchArray(this.validated[uri], schemaUri) !== -1;
  936. };
  937. /**
  938. * A wrapper class for binding an Environment, URI and helper methods to an instance.
  939. * This class is most commonly instantiated with {@link Environment#createInstance}.
  940. *
  941. * @name JSONInstance
  942. * @class
  943. * @param {Environment} env The environment this instance belongs to
  944. * @param {JSONInstance|Any} json The value of the instance
  945. * @param {String} [uri] The URI of the instance. If undefined, the URI will be a randomly generated UUID.
  946. * @param {String} [fd] The fragment delimiter for properties. If undefined, uses the environment default.
  947. */
  948. function JSONInstance(env, json, uri, fd) {
  949. if (json instanceof JSONInstance) {
  950. if (typeof fd !== "string") {
  951. fd = json._fd;
  952. }
  953. if (typeof uri !== "string") {
  954. uri = json._uri;
  955. }
  956. json = json._value;
  957. }
  958. if (typeof uri !== "string") {
  959. uri = "urn:uuid:" + randomUUID() + "#";
  960. } else if (uri.indexOf(":") === -1) {
  961. uri = formatURI(URI.resolve("urn:uuid:" + randomUUID() + "#", uri));
  962. }
  963. this._env = env;
  964. this._value = json;
  965. this._uri = uri;
  966. this._fd = fd || this._env._options["defaultFragmentDelimiter"];
  967. }
  968. /**
  969. * Returns the environment the instance is bound to.
  970. *
  971. * @returns {Environment} The environment of the instance
  972. */
  973. JSONInstance.prototype.getEnvironment = function () {
  974. return this._env;
  975. };
  976. /**
  977. * Returns the name of the type of the instance.
  978. *
  979. * @returns {String} The name of the type of the instance
  980. */
  981. JSONInstance.prototype.getType = function () {
  982. return typeOf(this._value);
  983. };
  984. /**
  985. * Returns the JSON value of the instance.
  986. *
  987. * @returns {Any} The actual JavaScript value of the instance
  988. */
  989. JSONInstance.prototype.getValue = function () {
  990. return this._value;
  991. };
  992. /**
  993. * Returns the URI of the instance.
  994. *
  995. * @returns {String} The URI of the instance
  996. */
  997. JSONInstance.prototype.getURI = function () {
  998. return this._uri;
  999. };
  1000. /**
  1001. * Returns a resolved URI of a provided relative URI against the URI of the instance.
  1002. *
  1003. * @param {String} uri The relative URI to resolve
  1004. * @returns {String} The resolved URI
  1005. */
  1006. JSONInstance.prototype.resolveURI = function (uri) {
  1007. return formatURI(URI.resolve(this._uri, uri));
  1008. };
  1009. /**
  1010. * Returns an array of the names of all the properties.
  1011. *
  1012. * @returns {Array} An array of strings which are the names of all the properties
  1013. */
  1014. JSONInstance.prototype.getPropertyNames = function () {
  1015. return keys(this._value);
  1016. };
  1017. /**
  1018. * Returns a {@link JSONInstance} of the value of the provided property name.
  1019. *
  1020. * @param {String} key The name of the property to fetch
  1021. * @returns {JSONInstance} The instance of the property value
  1022. */
  1023. JSONInstance.prototype.getProperty = function (key) {
  1024. var value = this._value ? this._value[key] : undefined;
  1025. if (value instanceof JSONInstance) {
  1026. return value;
  1027. }
  1028. //else
  1029. return new JSONInstance(this._env, value, this._uri + this._fd + escapeURIComponent(key), this._fd);
  1030. };
  1031. /**
  1032. * Returns all the property instances of the target instance.
  1033. * <p>
  1034. * If the target instance is an Object, then the method will return a hash table of {@link JSONInstance}s of all the properties.
  1035. * If the target instance is an Array, then the method will return an array of {@link JSONInstance}s of all the items.
  1036. * </p>
  1037. *
  1038. * @returns {Object|Array|undefined} The list of instances for all the properties
  1039. */
  1040. JSONInstance.prototype.getProperties = function () {
  1041. var type = typeOf(this._value),
  1042. self = this;
  1043. if (type === "object") {
  1044. return mapObject(this._value, function (value, key) {
  1045. if (value instanceof JSONInstance) {
  1046. return value;
  1047. }
  1048. return new JSONInstance(self._env, value, self._uri + self._fd + escapeURIComponent(key), self._fd);
  1049. });
  1050. } else if (type === "array") {
  1051. return mapArray(this._value, function (value, key) {
  1052. if (value instanceof JSONInstance) {
  1053. return value;
  1054. }
  1055. return new JSONInstance(self._env, value, self._uri + self._fd + escapeURIComponent(key), self._fd);
  1056. });
  1057. }
  1058. };
  1059. /**
  1060. * Returns the JSON value of the provided property name.
  1061. * This method is a faster version of calling <code>instance.getProperty(key).getValue()</code>.
  1062. *
  1063. * @param {String} key The name of the property
  1064. * @returns {Any} The JavaScript value of the instance
  1065. * @see JSONInstance#getProperty
  1066. * @see JSONInstance#getValue
  1067. */
  1068. JSONInstance.prototype.getValueOfProperty = function (key) {
  1069. if (this._value) {
  1070. if (this._value[key] instanceof JSONInstance) {
  1071. return this._value[key]._value;
  1072. }
  1073. return this._value[key];
  1074. }
  1075. };
  1076. /**
  1077. * Return if the provided value is the same as the value of the instance.
  1078. *
  1079. * @param {JSONInstance|Any} instance The value to compare
  1080. * @returns {Boolean} If both the instance and the value match
  1081. */
  1082. JSONInstance.prototype.equals = function (instance) {
  1083. if (instance instanceof JSONInstance) {
  1084. return this._value === instance._value;
  1085. }
  1086. //else
  1087. return this._value === instance;
  1088. };
  1089. /**
  1090. * Warning: Not a generic clone function
  1091. * Produces a JSV acceptable clone
  1092. */
  1093. function clone(obj, deep) {
  1094. var newObj, x;
  1095. if (obj instanceof JSONInstance) {
  1096. obj = obj.getValue();
  1097. }
  1098. switch (typeOf(obj)) {
  1099. case "object":
  1100. if (deep) {
  1101. newObj = {};
  1102. for (x in obj) {
  1103. if (obj[x] !== O[x]) {
  1104. newObj[x] = clone(obj[x], deep);
  1105. }
  1106. }
  1107. return newObj;
  1108. } else {
  1109. return createObject(obj);
  1110. }
  1111. break;
  1112. case "array":
  1113. if (deep) {
  1114. newObj = new Array(obj.length);
  1115. x = obj.length;
  1116. while (--x >= 0) {
  1117. newObj[x] = clone(obj[x], deep);
  1118. }
  1119. return newObj;
  1120. } else {
  1121. return Array.prototype.slice.call(obj);
  1122. }
  1123. break;
  1124. default:
  1125. return obj;
  1126. }
  1127. }
  1128. /**
  1129. * This class binds a {@link JSONInstance} with a {@link JSONSchema} to provided context aware methods.
  1130. *
  1131. * @name JSONSchema
  1132. * @class
  1133. * @param {Environment} env The environment this schema belongs to
  1134. * @param {JSONInstance|Any} json The value of the schema
  1135. * @param {String} [uri] The URI of the schema. If undefined, the URI will be a randomly generated UUID.
  1136. * @param {JSONSchema|Boolean} [schema] The schema to bind to the instance. If <code>undefined</code>, the environment's default schema will be used. If <code>true</code>, the instance's schema will be itself.
  1137. * @extends JSONInstance
  1138. */
  1139. function JSONSchema(env, json, uri, schema) {
  1140. var fr;
  1141. JSONInstance.call(this, env, json, uri);
  1142. if (schema === true) {
  1143. this._schema = this;
  1144. } else if (json instanceof JSONSchema && !(schema instanceof JSONSchema)) {
  1145. this._schema = json._schema; //TODO: Make sure cross environments don't mess everything up
  1146. } else {
  1147. this._schema = schema instanceof JSONSchema ? schema : this._env.getDefaultSchema() || JSONSchema.createEmptySchema(this._env);
  1148. }
  1149. //determine fragment delimiter from schema
  1150. fr = this._schema.getValueOfProperty("fragmentResolution");
  1151. if (fr === "dot-delimited") {
  1152. this._fd = ".";
  1153. } else if (fr === "slash-delimited") {
  1154. this._fd = "/";
  1155. }
  1156. }
  1157. JSONSchema.prototype = createObject(JSONInstance.prototype);
  1158. /**
  1159. * Creates an empty schema.
  1160. *
  1161. * @param {Environment} env The environment of the schema
  1162. * @returns {JSONSchema} The empty schema, who's schema is itself.
  1163. */
  1164. JSONSchema.createEmptySchema = function (env) {
  1165. var schema = createObject(JSONSchema.prototype);
  1166. JSONInstance.call(schema, env, {}, undefined, undefined);
  1167. schema._schema = schema;
  1168. return schema;
  1169. };
  1170. /**
  1171. * Returns the schema of the schema.
  1172. *
  1173. * @returns {JSONSchema} The schema of the schema
  1174. */
  1175. JSONSchema.prototype.getSchema = function () {
  1176. return this._schema;
  1177. };
  1178. /**
  1179. * Returns the value of the provided attribute name.
  1180. * <p>
  1181. * This method is different from {@link JSONInstance#getProperty} as the named property
  1182. * is converted using a parser defined by the schema's schema before being returned. This
  1183. * makes the return value of this method attribute dependent.
  1184. * </p>
  1185. *
  1186. * @param {String} key The name of the attribute
  1187. * @param {Any} [arg] Some attribute parsers accept special arguments for returning resolved values. This is attribute dependent.
  1188. * @returns {JSONSchema|Any} The value of the attribute
  1189. */
  1190. JSONSchema.prototype.getAttribute = function (key, arg) {
  1191. var schemaProperty, parser, property, result;
  1192. if (!arg && this._attributes && this._attributes.hasOwnProperty(key)) {
  1193. return this._attributes[key];
  1194. }
  1195. schemaProperty = this._schema.getProperty("properties").getProperty(key);
  1196. parser = schemaProperty.getValueOfProperty("parser");
  1197. property = this.getProperty(key);
  1198. if (typeof parser === "function") {
  1199. result = parser(property, schemaProperty, arg);
  1200. if (!arg && this._attributes) {
  1201. this._attributes[key] = result;
  1202. }
  1203. return result;
  1204. }
  1205. //else
  1206. return property.getValue();
  1207. };
  1208. /**
  1209. * Returns all the attributes of the schema.
  1210. *
  1211. * @returns {Object} A map of all parsed attribute values
  1212. */
  1213. JSONSchema.prototype.getAttributes = function () {
  1214. var properties, schemaProperties, key, schemaProperty, parser;
  1215. if (!this._attributes && this.getType() === "object") {
  1216. properties = this.getProperties();
  1217. schemaProperties = this._schema.getProperty("properties");
  1218. this._attributes = {};
  1219. for (key in properties) {
  1220. if (properties[key] !== O[key]) {
  1221. schemaProperty = schemaProperties && schemaProperties.getProperty(key);
  1222. parser = schemaProperty && schemaProperty.getValueOfProperty("parser");
  1223. if (typeof parser === "function") {
  1224. this._attributes[key] = parser(properties[key], schemaProperty);
  1225. } else {
  1226. this._attributes[key] = properties[key].getValue();
  1227. }
  1228. }
  1229. }
  1230. }
  1231. return clone(this._attributes, false);
  1232. };
  1233. /**
  1234. * Convenience method for retrieving a link or link object from a schema.
  1235. * This method is the same as calling <code>schema.getAttribute("links", [rel, instance])[0];</code>.
  1236. *
  1237. * @param {String} rel The link relationship
  1238. * @param {JSONInstance} [instance] The instance to resolve any URIs from
  1239. * @returns {String|Object|undefined} If <code>instance</code> is provided, a string containing the resolve URI of the link is returned.
  1240. * If <code>instance</code> is not provided, a link object is returned with details of the link.
  1241. * If no link with the provided relationship exists, <code>undefined</code> is returned.
  1242. * @see JSONSchema#getAttribute
  1243. */
  1244. JSONSchema.prototype.getLink = function (rel, instance) {
  1245. var schemaLinks = this.getAttribute("links", [rel, instance]);
  1246. if (schemaLinks && schemaLinks.length && schemaLinks[schemaLinks.length - 1]) {
  1247. return schemaLinks[schemaLinks.length - 1];
  1248. }
  1249. };
  1250. /**
  1251. * Validates the provided instance against the target schema and returns a {@link Report}.
  1252. *
  1253. * @param {JSONInstance|Any} instance The instance to validate; may be a {@link JSONInstance} or any JavaScript value
  1254. * @param {Report} [report] A {@link Report} to concatenate the result of the validation to. If <code>undefined</code>, a new {@link Report} is created.
  1255. * @param {JSONInstance} [parent] The parent/containing instance of the provided instance
  1256. * @param {JSONSchema} [parentSchema] The schema of the parent/containing instance
  1257. * @param {String} [name] The name of the parent object's property that references the instance
  1258. * @returns {Report} The result of the validation
  1259. */
  1260. JSONSchema.prototype.validate = function (instance, report, parent, parentSchema, name) {
  1261. var validator = this._schema.getValueOfProperty("validator");
  1262. if (!(instance instanceof JSONInstance)) {
  1263. instance = this.getEnvironment().createInstance(instance);
  1264. }
  1265. if (!(report instanceof Report)) {
  1266. report = new Report();
  1267. }
  1268. if (typeof validator === "function" && !report.isValidatedBy(instance.getURI(), this.getURI())) {
  1269. report.registerValidation(instance.getURI(), this.getURI());
  1270. validator(instance, this, this._schema, report, parent, parentSchema, name);
  1271. }
  1272. return report;
  1273. };
  1274. /**
  1275. * Merges two schemas/instances together.
  1276. */
  1277. function inherits(base, extra, extension) {
  1278. var baseType = typeOf(base),
  1279. extraType = typeOf(extra),
  1280. child, x;
  1281. if (extraType === "undefined") {
  1282. return clone(base, true);
  1283. } else if (baseType === "undefined" || extraType !== baseType) {
  1284. return clone(extra, true);
  1285. } else if (extraType === "object") {
  1286. if (base instanceof JSONSchema) {
  1287. base = base.getAttributes();
  1288. }
  1289. if (extra instanceof JSONSchema) {
  1290. extra = extra.getAttributes();
  1291. if (extra["extends"] && extension && extra["extends"] instanceof JSONSchema) {
  1292. extra["extends"] = [ extra["extends"] ];
  1293. }
  1294. }
  1295. child = clone(base, true); //this could be optimized as some properties get overwritten
  1296. for (x in extra) {
  1297. if (extra[x] !== O[x]) {
  1298. child[x] = inherits(base[x], extra[x], extension);
  1299. }
  1300. }
  1301. return child;
  1302. } else {
  1303. return clone(extra, true);
  1304. }
  1305. }
  1306. /**
  1307. * An Environment is a sandbox of schemas thats behavior is different from other environments.
  1308. *
  1309. * @name Environment
  1310. * @class
  1311. */
  1312. function Environment() {
  1313. this._id = randomUUID();
  1314. this._schemas = {};
  1315. this._options = {};
  1316. }
  1317. /**
  1318. * Returns a clone of the target environment.
  1319. *
  1320. * @returns {Environment} A new {@link Environment} that is a exact copy of the target environment
  1321. */
  1322. Environment.prototype.clone = function () {
  1323. var env = new Environment();
  1324. env._schemas = createObject(this._schemas);
  1325. env._options = createObject(this._options);
  1326. return env;
  1327. };
  1328. /**
  1329. * Returns a new {@link JSONInstance} of the provided data.
  1330. *
  1331. * @param {JSONInstance|Any} data The value of the instance
  1332. * @param {String} [uri] The URI of the instance. If undefined, the URI will be a randomly generated UUID.
  1333. * @returns {JSONInstance} A new {@link JSONInstance} from the provided data
  1334. */
  1335. Environment.prototype.createInstance = function (data, uri) {
  1336. var instance;
  1337. uri = formatURI(uri);
  1338. if (data instanceof JSONInstance && (!uri || data.getURI() === uri)) {
  1339. return data;
  1340. }
  1341. //else
  1342. instance = new JSONInstance(this, data, uri);
  1343. return instance;
  1344. };
  1345. /**
  1346. * Creates a new {@link JSONSchema} from the provided data, and registers it with the environment.
  1347. *
  1348. * @param {JSONInstance|Any} data The value of the schema
  1349. * @param {JSONSchema|Boolean} [schema] The schema to bind to the instance. If <code>undefined</code>, the environment's default schema will be used. If <code>true</code>, the instance's schema will be itself.
  1350. * @param {String} [uri] The URI of the schema. If undefined, the URI will be a randomly generated UUID.
  1351. * @returns {JSONSchema} A new {@link JSONSchema} from the provided data
  1352. * @throws {InitializationError} If a schema that is not registered with the environment is referenced
  1353. */
  1354. Environment.prototype.createSchema = function (data, schema, uri) {
  1355. var instance,
  1356. initializer;
  1357. uri = formatURI(uri);
  1358. if (data instanceof JSONSchema && (!uri || data._uri === uri) && (!schema || data._schema.equals(schema))) {
  1359. return data;
  1360. }
  1361. instance = new JSONSchema(this, data, uri, schema);
  1362. initializer = instance.getSchema().getValueOfProperty("initializer");
  1363. if (typeof initializer === "function") {
  1364. instance = initializer(instance);
  1365. }
  1366. //register schema
  1367. this._schemas[instance._uri] = instance;
  1368. this._schemas[uri] = instance;
  1369. //build & cache the rest of the schema
  1370. instance.getAttributes();
  1371. return instance;
  1372. };
  1373. /**
  1374. * Creates an empty schema.
  1375. *
  1376. * @param {Environment} env The environment of the schema
  1377. * @returns {JSONSchema} The empty schema, who's schema is itself.
  1378. */
  1379. Environment.prototype.createEmptySchema = function () {
  1380. var schema = JSONSchema.createEmptySchema(this);
  1381. this._schemas[schema._uri] = schema;
  1382. return schema;
  1383. };
  1384. /**
  1385. * Returns the schema registered with the provided URI.
  1386. *
  1387. * @param {String} uri The absolute URI of the required schema
  1388. * @returns {JSONSchema|undefined} The request schema, or <code>undefined</code> if not found
  1389. */
  1390. Environment.prototype.findSchema = function (uri) {
  1391. return this._schemas[formatURI(uri)];
  1392. };
  1393. /**
  1394. * Sets the specified environment option to the specified value.
  1395. *
  1396. * @param {String} name The name of the environment option to set
  1397. * @param {Any} value The new value of the environment option
  1398. */
  1399. Environment.prototype.setOption = function (name, value) {
  1400. this._options[name] = value;
  1401. };
  1402. /**
  1403. * Returns the specified environment option.
  1404. *
  1405. * @param {String} name The name of the environment option to set
  1406. * @returns {Any} The value of the environment option
  1407. */
  1408. Environment.prototype.getOption = function (name) {
  1409. return this._options[name];
  1410. };
  1411. /**
  1412. * Sets the default fragment delimiter of the environment.
  1413. *
  1414. * @deprecated Use {@link Environment#setOption} with option "defaultFragmentDelimiter"
  1415. * @param {String} fd The fragment delimiter character
  1416. */
  1417. Environment.prototype.setDefaultFragmentDelimiter = function (fd) {
  1418. if (typeof fd === "string" && fd.length > 0) {
  1419. this._options["defaultFragmentDelimiter"] = fd;
  1420. }
  1421. };
  1422. /**
  1423. * Returns the default fragment delimiter of the environment.
  1424. *
  1425. * @deprecated Use {@link Environment#getOption} with option "defaultFragmentDelimiter"
  1426. * @returns {String} The fragment delimiter character
  1427. */
  1428. Environment.prototype.getDefaultFragmentDelimiter = function () {
  1429. return this._options["defaultFragmentDelimiter"];
  1430. };
  1431. /**
  1432. * Sets the URI of the default schema for the environment.
  1433. *
  1434. * @deprecated Use {@link Environment#setOption} with option "defaultSchemaURI"
  1435. * @param {String} uri The default schema URI
  1436. */
  1437. Environment.prototype.setDefaultSchemaURI = function (uri) {
  1438. if (typeof uri === "string") {
  1439. this._options["defaultSchemaURI"] = formatURI(uri);
  1440. }
  1441. };
  1442. /**
  1443. * Returns the default schema of the environment.
  1444. *
  1445. * @returns {JSONSchema} The default schema
  1446. */
  1447. Environment.prototype.getDefaultSchema = function () {
  1448. return this.findSchema(this._options["defaultSchemaURI"]);
  1449. };
  1450. /**
  1451. * Validates both the provided schema and the provided instance, and returns a {@link Report}.
  1452. * If the schema fails to validate, the instance will not be validated.
  1453. *
  1454. * @param {JSONInstance|Any} instanceJSON The {@link JSONInstance} or JavaScript value to validate.
  1455. * @param {JSONSchema|Any} schemaJSON The {@link JSONSchema} or JavaScript value to use in the validation. This will also be validated againt the schema's schema.
  1456. * @returns {Report} The result of the validation
  1457. */
  1458. Environment.prototype.validate = function (instanceJSON, schemaJSON) {
  1459. var instance,
  1460. schema,
  1461. schemaSchema,
  1462. report = new Report();
  1463. try {
  1464. instance = this.createInstance(instanceJSON);
  1465. report.instance = instance;
  1466. } catch (e) {
  1467. report.addError(e.uri, e.schemaUri, e.attribute, e.message, e.details);
  1468. }
  1469. try {
  1470. schema = this.createSchema(schemaJSON);
  1471. report.schema = schema;
  1472. schemaSchema = schema.getSchema();
  1473. report.schemaSchema = schemaSchema;
  1474. } catch (e) {
  1475. report.addError(e.uri, e.schemaUri, e.attribute, e.message, e.details);
  1476. }
  1477. if (schemaSchema) {
  1478. schemaSchema.validate(schema, report);
  1479. }
  1480. if (report.errors.length) {
  1481. return report;
  1482. }
  1483. return schema.validate(instance, report);
  1484. };
  1485. /**
  1486. * @private
  1487. */
  1488. Environment.prototype._checkForInvalidInstances = function (stackSize, schemaURI) {
  1489. var result = [],
  1490. stack = [
  1491. [schemaURI, this._schemas[schemaURI]]
  1492. ],
  1493. counter = 0,
  1494. item, uri, instance, schema, properties, key;
  1495. while (counter++ < stackSize && stack.length) {
  1496. item = stack.shift();
  1497. uri = item[0];
  1498. instance = item[1];
  1499. if (instance instanceof JSONSchema) {
  1500. if (this._schemas[instance._uri] !== instance) {
  1501. result.push("Instance " + uri + " does not match " + instance._uri);
  1502. } else {
  1503. //schema = instance.getSchema();
  1504. //stack.push([uri + "/{schema}", schema]);
  1505. properties = instance.getAttributes();
  1506. for (key in properties) {
  1507. if (properties[key] !== O[key]) {
  1508. stack.push([uri + "/" + escapeURIComponent(key), properties[key]]);
  1509. }
  1510. }
  1511. }
  1512. } else if (typeOf(instance) === "object") {
  1513. properties = instance;
  1514. for (key in properties) {
  1515. if (properties.hasOwnProperty(key)) {
  1516. stack.push([uri + "/" + escapeURIComponent(key), properties[key]]);
  1517. }
  1518. }
  1519. } else if (typeOf(instance) === "array") {
  1520. properties = instance;
  1521. for (key = 0; key < properties.length; ++key) {
  1522. stack.push([uri + "/" + escapeURIComponent(key), properties[key]]);
  1523. }
  1524. }
  1525. }
  1526. return result.length ? result : counter;
  1527. };
  1528. /**
  1529. * A globaly accessible object that provides the ability to create and manage {@link Environments},
  1530. * as well as providing utility methods.
  1531. *
  1532. * @namespace
  1533. */
  1534. JSV = {
  1535. _environments : {},
  1536. _defaultEnvironmentID : "",
  1537. /**
  1538. * Returns if the provide value is an instance of {@link JSONInstance}.
  1539. *
  1540. * @param o The value to test
  1541. * @returns {Boolean} If the provide value is an instance of {@link JSONInstance}
  1542. */
  1543. isJSONInstance : function (o) {
  1544. return o instanceof JSONInstance;
  1545. },
  1546. /**
  1547. * Returns if the provide value is an instance of {@link JSONSchema}.
  1548. *
  1549. * @param o The value to test
  1550. * @returns {Boolean} If the provide value is an instance of {@link JSONSchema}
  1551. */
  1552. isJSONSchema : function (o) {
  1553. return o instanceof JSONSchema;
  1554. },
  1555. /**
  1556. * Creates and returns a new {@link Environment} that is a clone of the environment registered with the provided ID.
  1557. * If no environment ID is provided, the default environment is cloned.
  1558. *
  1559. * @param {String} [id] The ID of the environment to clone. If <code>undefined</code>, the default environment ID is used.
  1560. * @returns {Environment} A newly cloned {@link Environment}
  1561. * @throws {Error} If there is no environment registered with the provided ID
  1562. */
  1563. createEnvironment : function (id) {
  1564. id = id || this._defaultEnvironmentID;
  1565. if (!this._environments[id]) {
  1566. throw new Error("Unknown Environment ID");
  1567. }
  1568. //else
  1569. return this._environments[id].clone();
  1570. },
  1571. Environment : Environment,
  1572. /**
  1573. * Registers the provided {@link Environment} with the provided ID.
  1574. *
  1575. * @param {String} id The ID of the environment
  1576. * @param {Environment} env The environment to register
  1577. */
  1578. registerEnvironment : function (id, env) {
  1579. id = id || (env || 0)._id;
  1580. if (id && !this._environments[id] && env instanceof Environment) {
  1581. env._id = id;
  1582. this._environments[id] = env;
  1583. }
  1584. },
  1585. /**
  1586. * Sets which registered ID is the default environment.
  1587. *
  1588. * @param {String} id The ID of the registered environment that is default
  1589. * @throws {Error} If there is no registered environment with the provided ID
  1590. */
  1591. setDefaultEnvironmentID : function (id) {
  1592. if (typeof id === "string") {
  1593. if (!this._environments[id]) {
  1594. throw new Error("Unknown Environment ID");
  1595. }
  1596. this._defaultEnvironmentID = id;
  1597. }
  1598. },
  1599. /**
  1600. * Returns the ID of the default environment.
  1601. *
  1602. * @returns {String} The ID of the default environment
  1603. */
  1604. getDefaultEnvironmentID : function () {
  1605. return this._defaultEnvironmentID;
  1606. },
  1607. //
  1608. // Utility Functions
  1609. //
  1610. /**
  1611. * Returns the name of the type of the provided value.
  1612. *
  1613. * @event //utility
  1614. * @param {Any} o The value to determine the type of
  1615. * @returns {String} The name of the type of the value
  1616. */
  1617. typeOf : typeOf,
  1618. /**
  1619. * Return a new object that inherits all of the properties of the provided object.
  1620. *
  1621. * @event //utility
  1622. * @param {Object} proto The prototype of the new object
  1623. * @returns {Object} A new object that inherits all of the properties of the provided object
  1624. */
  1625. createObject : createObject,
  1626. /**
  1627. * Returns a new object with each property transformed by the iterator.
  1628. *
  1629. * @event //utility
  1630. * @param {Object} obj The object to transform
  1631. * @param {Function} iterator A function that returns the new value of the provided property
  1632. * @param {Object} [scope] The value of <code>this</code> in the iterator
  1633. * @returns {Object} A new object with each property transformed
  1634. */
  1635. mapObject : mapObject,
  1636. /**
  1637. * Returns a new array with each item transformed by the iterator.
  1638. *
  1639. * @event //utility
  1640. * @param {Array} arr The array to transform
  1641. * @param {Function} iterator A function that returns the new value of the provided item
  1642. * @param {Object} scope The value of <code>this</code> in the iterator
  1643. * @returns {Array} A new array with each item transformed
  1644. */
  1645. mapArray : mapArray,
  1646. /**
  1647. * Returns a new array that only contains the items allowed by the iterator.
  1648. *
  1649. * @event //utility
  1650. * @param {Array} arr The array to filter
  1651. * @param {Function} iterator The function that returns true if the provided property should be added to the array
  1652. * @param {Object} scope The value of <code>this</code> within the iterator
  1653. * @returns {Array} A new array that contains the items allowed by the iterator
  1654. */
  1655. filterArray : filterArray,
  1656. /**
  1657. * Returns the first index in the array that the provided item is located at.
  1658. *
  1659. * @event //utility
  1660. * @param {Array} arr The array to search
  1661. * @param {Any} o The item being searched for
  1662. * @returns {Number} The index of the item in the array, or <code>-1</code> if not found
  1663. */
  1664. searchArray : searchArray,
  1665. /**
  1666. * Returns an array representation of a value.
  1667. * <ul>
  1668. * <li>For array-like objects, the value will be casted as an Array type.</li>
  1669. * <li>If an array is provided, the function will simply return the same array.</li>
  1670. * <li>For a null or undefined value, the result will be an empty Array.</li>
  1671. * <li>For all other values, the value will be the first element in a new Array. </li>
  1672. * </ul>
  1673. *
  1674. * @event //utility
  1675. * @param {Any} o The value to convert into an array
  1676. * @returns {Array} The value as an array
  1677. */
  1678. toArray : toArray,
  1679. /**
  1680. * Returns an array of the names of all properties of an object.
  1681. *
  1682. * @event //utility
  1683. * @param {Object|Array} o The object in question
  1684. * @returns {Array} The names of all properties
  1685. */
  1686. keys : keys,
  1687. /**
  1688. * Mutates the array by pushing the provided value onto the array only if it is not already there.
  1689. *
  1690. * @event //utility
  1691. * @param {Array} arr The array to modify
  1692. * @param {Any} o The object to add to the array if it is not already there
  1693. * @returns {Array} The provided array for chaining
  1694. */
  1695. pushUnique : pushUnique,
  1696. /**
  1697. * Mutates the array by removing the first item that matches the provided value in the array.
  1698. *
  1699. * @event //utility
  1700. * @param {Array} arr The array to modify
  1701. * @param {Any} o The object to remove from the array
  1702. * @returns {Array} The provided array for chaining
  1703. */
  1704. popFirst : popFirst,
  1705. /**
  1706. * Creates a copy of the target object.
  1707. * <p>
  1708. * This method will create a new instance of the target, and then mixin the properties of the target.
  1709. * If <code>deep</code> is <code>true</code>, then each property will be cloned before mixin.
  1710. * </p>
  1711. * <p><b>Warning</b>: This is not a generic clone function, as it will only properly clone objects and arrays.</p>
  1712. *
  1713. * @event //utility
  1714. * @param {Any} o The value to clone
  1715. * @param {Boolean} [deep=false] If each property should be recursively cloned
  1716. * @returns A cloned copy of the provided value
  1717. */
  1718. clone : clone,
  1719. /**
  1720. * Generates a pseudo-random UUID.
  1721. *
  1722. * @event //utility
  1723. * @returns {String} A new universally unique ID
  1724. */
  1725. randomUUID : randomUUID,
  1726. /**
  1727. * Properly escapes a URI component for embedding into a URI string.
  1728. *
  1729. * @event //utility
  1730. * @param {String} str The URI component to escape
  1731. * @returns {String} The escaped URI component
  1732. */
  1733. escapeURIComponent : escapeURIComponent,
  1734. /**
  1735. * Returns a URI that is formated for JSV. Currently, this only ensures that the URI ends with a hash tag (<code>#</code>).
  1736. *
  1737. * @event //utility
  1738. * @param {String} uri The URI to format
  1739. * @returns {String} The URI formatted for JSV
  1740. */
  1741. formatURI : formatURI,
  1742. /**
  1743. * Merges two schemas/instance together.
  1744. *
  1745. * @event //utility
  1746. * @param {JSONSchema|Any} base The old value to merge
  1747. * @param {JSONSchema|Any} extra The new value to merge
  1748. * @param {Boolean} extension If the merge is a JSON Schema extension
  1749. * @return {Any} The modified base value
  1750. */
  1751. inherits : inherits
  1752. };
  1753. this.JSV = JSV; //set global object
  1754. exports.JSV = JSV; //export to CommonJS
  1755. require("./environments"); //load default environments
  1756. }());
  1757. /**
  1758. * json-schema-draft-03 Environment
  1759. *
  1760. * @fileOverview Implementation of the third revision of the JSON Schema specification draft.
  1761. * @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
  1762. * @version 1.3
  1763. * @see http://github.com/garycourt/JSV
  1764. */
  1765. /*
  1766. * Copyright 2010 Gary Court. All rights reserved.
  1767. *
  1768. * Redistribution and use in source and binary forms, with or without modification, are
  1769. * permitted provided that the following conditions are met:
  1770. *
  1771. * 1. Redistributions of source code must retain the above copyright notice, this list of
  1772. * conditions and the following disclaimer.
  1773. *
  1774. * 2. Redistributions in binary form must reproduce the above copyright notice, this list
  1775. * of conditions and the following disclaimer in the documentation and/or other materials
  1776. * provided with the distribution.
  1777. *
  1778. * THIS SOFTWARE IS PROVIDED BY GARY COURT ``AS IS'' AND ANY EXPRESS OR IMPLIED
  1779. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  1780. * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARY COURT OR
  1781. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  1782. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  1783. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  1784. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  1785. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  1786. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1787. *
  1788. * The views and conclusions contained in the software and documentation are those of the
  1789. * authors and should not be interpreted as representing official policies, either expressed
  1790. * or implied, of Gary Court or the JSON Schema specification.
  1791. */
  1792. /*jslint white: true, sub: true, onevar: true, undef: true, eqeqeq: true, newcap: true, immed: true, indent: 4 */
  1793. /*global require */
  1794. (function () {
  1795. var O = {},
  1796. JSV = require('./jsv').JSV,
  1797. InitializationError,
  1798. TYPE_VALIDATORS,
  1799. ENVIRONMENT,
  1800. SCHEMA_00_JSON,
  1801. HYPERSCHEMA_00_JSON,
  1802. LINKS_00_JSON,
  1803. SCHEMA_00,
  1804. HYPERSCHEMA_00,
  1805. LINKS_00,
  1806. SCHEMA_01_JSON,
  1807. HYPERSCHEMA_01_JSON,
  1808. LINKS_01_JSON,
  1809. SCHEMA_01,
  1810. HYPERSCHEMA_01,
  1811. LINKS_01,
  1812. SCHEMA_02_JSON,
  1813. HYPERSCHEMA_02_JSON,
  1814. LINKS_02_JSON,
  1815. SCHEMA_02,
  1816. HYPERSCHEMA_02,
  1817. LINKS_02,
  1818. SCHEMA_03_JSON,
  1819. HYPERSCHEMA_03_JSON,
  1820. LINKS_03_JSON,
  1821. SCHEMA_03,
  1822. HYPERSCHEMA_03,
  1823. LINKS_03;
  1824. InitializationError = function InitializationError(instance, schema, attr, message, details) {
  1825. Error.call(this, message);
  1826. this.uri = instance.getURI();
  1827. this.schemaUri = schema.getURI();
  1828. this.attribute = attr;
  1829. this.message = message;
  1830. this.description = message; //IE
  1831. this.details = details;
  1832. }
  1833. InitializationError.prototype = new Error();
  1834. InitializationError.prototype.constructor = InitializationError;
  1835. InitializationError.prototype.name = "InitializationError";
  1836. TYPE_VALIDATORS = {
  1837. "string" : function (instance, report) {
  1838. return instance.getType() === "string";
  1839. },
  1840. "number" : function (instance, report) {
  1841. return instance.getType() === "number";
  1842. },
  1843. "integer" : function (instance, report) {
  1844. return instance.getType() === "number" && instance.getValue() % 1 === 0;
  1845. },
  1846. "boolean" : function (instance, report) {
  1847. return instance.getType() === "boolean";
  1848. },
  1849. "object" : function (instance, report) {
  1850. return instance.getType() === "object";
  1851. },
  1852. "array" : function (instance, report) {
  1853. return instance.getType() === "array";
  1854. },
  1855. "null" : function (instance, report) {
  1856. return instance.getType() === "null";
  1857. },
  1858. "any" : function (instance, report) {
  1859. return true;
  1860. }
  1861. };
  1862. ENVIRONMENT = new JSV.Environment();
  1863. ENVIRONMENT.setOption("strict", false);
  1864. ENVIRONMENT.setOption("validateReferences", false); //updated later
  1865. //
  1866. // draft-00
  1867. //
  1868. SCHEMA_00_JSON = {
  1869. "$schema" : "http://json-schema.org/draft-00/hyper-schema#",
  1870. "id" : "http://json-schema.org/draft-00/schema#",
  1871. "type" : "object",
  1872. "properties" : {
  1873. "type" : {
  1874. "type" : ["string", "array"],
  1875. "items" : {
  1876. "type" : ["string", {"$ref" : "#"}]
  1877. },
  1878. "optional" : true,
  1879. "uniqueItems" : true,
  1880. "default" : "any",
  1881. "parser" : function (instance, self) {
  1882. var parser;
  1883. if (instance.getType() === "string") {
  1884. return instance.getValue();
  1885. } else if (instance.getType() === "object") {
  1886. return instance.getEnvironment().createSchema(
  1887. instance,
  1888. self.getEnvironment().findSchema(self.resolveURI("#"))
  1889. );
  1890. } else if (instance.getType() === "array") {
  1891. parser = self.getValueOfProperty("parser");
  1892. return JSV.mapArray(instance.getProperties(), function (prop) {
  1893. return parser(prop, self);
  1894. });
  1895. }
  1896. //else
  1897. return "any";
  1898. },
  1899. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1900. var requiredTypes = JSV.toArray(schema.getAttribute("type")),
  1901. x, xl, type, subreport, typeValidators;
  1902. //for instances that are required to be a certain type
  1903. if (instance.getType() !== "undefined" && requiredTypes && requiredTypes.length) {
  1904. typeValidators = self.getValueOfProperty("typeValidators") || {};
  1905. //ensure that type matches for at least one of the required types
  1906. for (x = 0, xl = requiredTypes.length; x < xl; ++x) {
  1907. type = requiredTypes[x];
  1908. if (JSV.isJSONSchema(type)) {
  1909. subreport = JSV.createObject(report);
  1910. subreport.errors = [];
  1911. subreport.validated = JSV.clone(report.validated);
  1912. if (type.validate(instance, subreport, parent, parentSchema, name).errors.length === 0) {
  1913. return true; //instance matches this schema
  1914. }
  1915. } else {
  1916. if (typeValidators[type] !== O[type] && typeof typeValidators[type] === "function") {
  1917. if (typeValidators[type](instance, report)) {
  1918. return true; //type is valid
  1919. }
  1920. } else {
  1921. return true; //unknown types are assumed valid
  1922. }
  1923. }
  1924. }
  1925. //if we get to this point, type is invalid
  1926. report.addError(instance, schema, "type", "Instance is not a required type", requiredTypes);
  1927. return false;
  1928. }
  1929. //else, anything is allowed if no type is specified
  1930. return true;
  1931. },
  1932. "typeValidators" : TYPE_VALIDATORS
  1933. },
  1934. "properties" : {
  1935. "type" : "object",
  1936. "additionalProperties" : {"$ref" : "#"},
  1937. "optional" : true,
  1938. "default" : {},
  1939. "parser" : function (instance, self, arg) {
  1940. var env = instance.getEnvironment(),
  1941. selfEnv = self.getEnvironment();
  1942. if (instance.getType() === "object") {
  1943. if (arg) {
  1944. return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI("#")));
  1945. } else {
  1946. return JSV.mapObject(instance.getProperties(), function (instance) {
  1947. return env.createSchema(instance, selfEnv.findSchema(self.resolveURI("#")));
  1948. });
  1949. }
  1950. }
  1951. //else
  1952. return {};
  1953. },
  1954. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1955. var propertySchemas, key;
  1956. //this attribute is for object type instances only
  1957. if (instance.getType() === "object") {
  1958. //for each property defined in the schema
  1959. propertySchemas = schema.getAttribute("properties");
  1960. for (key in propertySchemas) {
  1961. if (propertySchemas[key] !== O[key] && propertySchemas[key]) {
  1962. //ensure that instance property is valid
  1963. propertySchemas[key].validate(instance.getProperty(key), report, instance, schema, key);
  1964. }
  1965. }
  1966. }
  1967. }
  1968. },
  1969. "items" : {
  1970. "type" : [{"$ref" : "#"}, "array"],
  1971. "items" : {"$ref" : "#"},
  1972. "optional" : true,
  1973. "default" : {},
  1974. "parser" : function (instance, self) {
  1975. if (instance.getType() === "object") {
  1976. return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  1977. } else if (instance.getType() === "array") {
  1978. return JSV.mapArray(instance.getProperties(), function (instance) {
  1979. return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  1980. });
  1981. }
  1982. //else
  1983. return instance.getEnvironment().createEmptySchema();
  1984. },
  1985. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  1986. var properties, items, x, xl, itemSchema, additionalProperties;
  1987. if (instance.getType() === "array") {
  1988. properties = instance.getProperties();
  1989. items = schema.getAttribute("items");
  1990. additionalProperties = schema.getAttribute("additionalProperties");
  1991. if (JSV.typeOf(items) === "array") {
  1992. for (x = 0, xl = properties.length; x < xl; ++x) {
  1993. itemSchema = items[x] || additionalProperties;
  1994. if (itemSchema !== false) {
  1995. itemSchema.validate(properties[x], report, instance, schema, x);
  1996. } else {
  1997. report.addError(instance, schema, "additionalProperties", "Additional items are not allowed", itemSchema);
  1998. }
  1999. }
  2000. } else {
  2001. itemSchema = items || additionalProperties;
  2002. for (x = 0, xl = properties.length; x < xl; ++x) {
  2003. itemSchema.validate(properties[x], report, instance, schema, x);
  2004. }
  2005. }
  2006. }
  2007. }
  2008. },
  2009. "optional" : {
  2010. "type" : "boolean",
  2011. "optional" : true,
  2012. "default" : false,
  2013. "parser" : function (instance, self) {
  2014. return !!instance.getValue();
  2015. },
  2016. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2017. if (instance.getType() === "undefined" && !schema.getAttribute("optional")) {
  2018. report.addError(instance, schema, "optional", "Property is required", false);
  2019. }
  2020. },
  2021. "validationRequired" : true
  2022. },
  2023. "additionalProperties" : {
  2024. "type" : [{"$ref" : "#"}, "boolean"],
  2025. "optional" : true,
  2026. "default" : {},
  2027. "parser" : function (instance, self) {
  2028. if (instance.getType() === "object") {
  2029. return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  2030. } else if (instance.getType() === "boolean" && instance.getValue() === false) {
  2031. return false;
  2032. }
  2033. //else
  2034. return instance.getEnvironment().createEmptySchema();
  2035. },
  2036. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2037. var additionalProperties, propertySchemas, properties, key;
  2038. //we only need to check against object types as arrays do their own checking on this property
  2039. if (instance.getType() === "object") {
  2040. additionalProperties = schema.getAttribute("additionalProperties");
  2041. propertySchemas = schema.getAttribute("properties") || {};
  2042. properties = instance.getProperties();
  2043. for (key in properties) {
  2044. if (properties[key] !== O[key] && properties[key] && propertySchemas[key] === O[key]) {
  2045. if (JSV.isJSONSchema(additionalProperties)) {
  2046. additionalProperties.validate(properties[key], report, instance, schema, key);
  2047. } else if (additionalProperties === false) {
  2048. report.addError(instance, schema, "additionalProperties", "Additional properties are not allowed", additionalProperties);
  2049. }
  2050. }
  2051. }
  2052. }
  2053. }
  2054. },
  2055. "requires" : {
  2056. "type" : ["string", {"$ref" : "#"}],
  2057. "optional" : true,
  2058. "parser" : function (instance, self) {
  2059. if (instance.getType() === "string") {
  2060. return instance.getValue();
  2061. } else if (instance.getType() === "object") {
  2062. return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  2063. }
  2064. },
  2065. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2066. var requires;
  2067. if (instance.getType() !== "undefined" && parent && parent.getType() !== "undefined") {
  2068. requires = schema.getAttribute("requires");
  2069. if (typeof requires === "string") {
  2070. if (parent.getProperty(requires).getType() === "undefined") {
  2071. report.addError(instance, schema, "requires", 'Property requires sibling property "' + requires + '"', requires);
  2072. }
  2073. } else if (JSV.isJSONSchema(requires)) {
  2074. requires.validate(parent, report); //WATCH: A "requires" schema does not support the "requires" attribute
  2075. }
  2076. }
  2077. }
  2078. },
  2079. "minimum" : {
  2080. "type" : "number",
  2081. "optional" : true,
  2082. "parser" : function (instance, self) {
  2083. if (instance.getType() === "number") {
  2084. return instance.getValue();
  2085. }
  2086. },
  2087. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2088. var minimum, minimumCanEqual;
  2089. if (instance.getType() === "number") {
  2090. minimum = schema.getAttribute("minimum");
  2091. minimumCanEqual = schema.getAttribute("minimumCanEqual");
  2092. if (typeof minimum === "number" && (instance.getValue() < minimum || (minimumCanEqual === false && instance.getValue() === minimum))) {
  2093. report.addError(instance, schema, "minimum", "Number is less then the required minimum value", minimum);
  2094. }
  2095. }
  2096. }
  2097. },
  2098. "maximum" : {
  2099. "type" : "number",
  2100. "optional" : true,
  2101. "parser" : function (instance, self) {
  2102. if (instance.getType() === "number") {
  2103. return instance.getValue();
  2104. }
  2105. },
  2106. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2107. var maximum, maximumCanEqual;
  2108. if (instance.getType() === "number") {
  2109. maximum = schema.getAttribute("maximum");
  2110. maximumCanEqual = schema.getAttribute("maximumCanEqual");
  2111. if (typeof maximum === "number" && (instance.getValue() > maximum || (maximumCanEqual === false && instance.getValue() === maximum))) {
  2112. report.addError(instance, schema, "maximum", "Number is greater then the required maximum value", maximum);
  2113. }
  2114. }
  2115. }
  2116. },
  2117. "minimumCanEqual" : {
  2118. "type" : "boolean",
  2119. "optional" : true,
  2120. "requires" : "minimum",
  2121. "default" : true,
  2122. "parser" : function (instance, self) {
  2123. if (instance.getType() === "boolean") {
  2124. return instance.getValue();
  2125. }
  2126. //else
  2127. return true;
  2128. }
  2129. },
  2130. "maximumCanEqual" : {
  2131. "type" : "boolean",
  2132. "optional" : true,
  2133. "requires" : "maximum",
  2134. "default" : true,
  2135. "parser" : function (instance, self) {
  2136. if (instance.getType() === "boolean") {
  2137. return instance.getValue();
  2138. }
  2139. //else
  2140. return true;
  2141. }
  2142. },
  2143. "minItems" : {
  2144. "type" : "integer",
  2145. "optional" : true,
  2146. "minimum" : 0,
  2147. "default" : 0,
  2148. "parser" : function (instance, self) {
  2149. if (instance.getType() === "number") {
  2150. return instance.getValue();
  2151. }
  2152. //else
  2153. return 0;
  2154. },
  2155. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2156. var minItems;
  2157. if (instance.getType() === "array") {
  2158. minItems = schema.getAttribute("minItems");
  2159. if (typeof minItems === "number" && instance.getProperties().length < minItems) {
  2160. report.addError(instance, schema, "minItems", "The number of items is less then the required minimum", minItems);
  2161. }
  2162. }
  2163. }
  2164. },
  2165. "maxItems" : {
  2166. "type" : "integer",
  2167. "optional" : true,
  2168. "minimum" : 0,
  2169. "parser" : function (instance, self) {
  2170. if (instance.getType() === "number") {
  2171. return instance.getValue();
  2172. }
  2173. },
  2174. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2175. var maxItems;
  2176. if (instance.getType() === "array") {
  2177. maxItems = schema.getAttribute("maxItems");
  2178. if (typeof maxItems === "number" && instance.getProperties().length > maxItems) {
  2179. report.addError(instance, schema, "maxItems", "The number of items is greater then the required maximum", maxItems);
  2180. }
  2181. }
  2182. }
  2183. },
  2184. "pattern" : {
  2185. "type" : "string",
  2186. "optional" : true,
  2187. "format" : "regex",
  2188. "parser" : function (instance, self) {
  2189. if (instance.getType() === "string") {
  2190. try {
  2191. return new RegExp(instance.getValue());
  2192. } catch (e) {
  2193. return e;
  2194. }
  2195. }
  2196. },
  2197. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2198. var pattern;
  2199. try {
  2200. pattern = schema.getAttribute("pattern");
  2201. if (pattern instanceof Error) {
  2202. report.addError(schema, self, "pattern", "Invalid pattern", schema.getValueOfProperty("pattern"));
  2203. } else if (instance.getType() === "string" && pattern && !pattern.test(instance.getValue())) {
  2204. report.addError(instance, schema, "pattern", "String does not match pattern", pattern.toString());
  2205. }
  2206. } catch (e) {
  2207. report.addError(schema, self, "pattern", "Invalid pattern", schema.getValueOfProperty("pattern"));
  2208. }
  2209. }
  2210. },
  2211. "minLength" : {
  2212. "type" : "integer",
  2213. "optional" : true,
  2214. "minimum" : 0,
  2215. "default" : 0,
  2216. "parser" : function (instance, self) {
  2217. if (instance.getType() === "number") {
  2218. return instance.getValue();
  2219. }
  2220. //else
  2221. return 0;
  2222. },
  2223. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2224. var minLength;
  2225. if (instance.getType() === "string") {
  2226. minLength = schema.getAttribute("minLength");
  2227. if (typeof minLength === "number" && instance.getValue().length < minLength) {
  2228. report.addError(instance, schema, "minLength", "String is less then the required minimum length", minLength);
  2229. }
  2230. }
  2231. }
  2232. },
  2233. "maxLength" : {
  2234. "type" : "integer",
  2235. "optional" : true,
  2236. "parser" : function (instance, self) {
  2237. if (instance.getType() === "number") {
  2238. return instance.getValue();
  2239. }
  2240. },
  2241. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2242. var maxLength;
  2243. if (instance.getType() === "string") {
  2244. maxLength = schema.getAttribute("maxLength");
  2245. if (typeof maxLength === "number" && instance.getValue().length > maxLength) {
  2246. report.addError(instance, schema, "maxLength", "String is greater then the required maximum length", maxLength);
  2247. }
  2248. }
  2249. }
  2250. },
  2251. "enum" : {
  2252. "type" : "array",
  2253. "optional" : true,
  2254. "minItems" : 1,
  2255. "uniqueItems" : true,
  2256. "parser" : function (instance, self) {
  2257. if (instance.getType() === "array") {
  2258. return instance.getValue();
  2259. }
  2260. },
  2261. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2262. var enums, x, xl;
  2263. if (instance.getType() !== "undefined") {
  2264. enums = schema.getAttribute("enum");
  2265. if (enums) {
  2266. for (x = 0, xl = enums.length; x < xl; ++x) {
  2267. if (instance.equals(enums[x])) {
  2268. return true;
  2269. }
  2270. }
  2271. report.addError(instance, schema, "enum", "Instance is not one of the possible values", enums);
  2272. }
  2273. }
  2274. }
  2275. },
  2276. "title" : {
  2277. "type" : "string",
  2278. "optional" : true
  2279. },
  2280. "description" : {
  2281. "type" : "string",
  2282. "optional" : true
  2283. },
  2284. "format" : {
  2285. "type" : "string",
  2286. "optional" : true,
  2287. "parser" : function (instance, self) {
  2288. if (instance.getType() === "string") {
  2289. return instance.getValue();
  2290. }
  2291. },
  2292. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2293. var format, formatValidators;
  2294. if (instance.getType() === "string") {
  2295. format = schema.getAttribute("format");
  2296. formatValidators = self.getValueOfProperty("formatValidators");
  2297. if (typeof format === "string" && formatValidators[format] !== O[format] && typeof formatValidators[format] === "function" && !formatValidators[format].call(this, instance, report)) {
  2298. report.addError(instance, schema, "format", "String is not in the required format", format);
  2299. }
  2300. }
  2301. },
  2302. // JOSHFIRE: added a couple of format validators for "uri" and "email"
  2303. "formatValidators" : {
  2304. "uri": function (instance, report) {
  2305. // Regular expression from @diegoperini taken from:
  2306. // http://mathiasbynens.be/demo/url-regex
  2307. // ... and only slightly adjusted for use in JavaScript
  2308. var reUri = /^(?:(?:https?):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+\-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+\-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i;
  2309. return !!reUri.test(instance._value);
  2310. },
  2311. "email": function (instance, report) {
  2312. // Regular expression taken from:
  2313. // http://www.regular-expressions.info/email.html
  2314. var reEmail = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
  2315. return !!reEmail.test(instance._value);
  2316. }
  2317. }
  2318. // JOSHFIRE: end of custom code
  2319. // "formatValidators": {}
  2320. },
  2321. "contentEncoding" : {
  2322. "type" : "string",
  2323. "optional" : true
  2324. },
  2325. "default" : {
  2326. "type" : "any",
  2327. "optional" : true
  2328. },
  2329. "maxDecimal" : {
  2330. "type" : "integer",
  2331. "optional" : true,
  2332. "minimum" : 0,
  2333. "parser" : function (instance, self) {
  2334. if (instance.getType() === "number") {
  2335. return instance.getValue();
  2336. }
  2337. },
  2338. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2339. var maxDecimal, decimals;
  2340. if (instance.getType() === "number") {
  2341. maxDecimal = schema.getAttribute("maxDecimal");
  2342. if (typeof maxDecimal === "number") {
  2343. decimals = instance.getValue().toString(10).split('.')[1];
  2344. if (decimals && decimals.length > maxDecimal) {
  2345. report.addError(instance, schema, "maxDecimal", "The number of decimal places is greater then the allowed maximum", maxDecimal);
  2346. }
  2347. }
  2348. }
  2349. }
  2350. },
  2351. "disallow" : {
  2352. "type" : ["string", "array"],
  2353. "items" : {"type" : "string"},
  2354. "optional" : true,
  2355. "uniqueItems" : true,
  2356. "parser" : function (instance, self) {
  2357. if (instance.getType() === "string" || instance.getType() === "array") {
  2358. return instance.getValue();
  2359. }
  2360. },
  2361. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2362. var disallowedTypes = JSV.toArray(schema.getAttribute("disallow")),
  2363. x, xl, key, typeValidators, subreport;
  2364. //for instances that are required to be a certain type
  2365. if (instance.getType() !== "undefined" && disallowedTypes && disallowedTypes.length) {
  2366. typeValidators = self.getValueOfProperty("typeValidators") || {};
  2367. //ensure that type matches for at least one of the required types
  2368. for (x = 0, xl = disallowedTypes.length; x < xl; ++x) {
  2369. key = disallowedTypes[x];
  2370. if (JSV.isJSONSchema(key)) { //this is supported draft-03 and on
  2371. subreport = JSV.createObject(report);
  2372. subreport.errors = [];
  2373. subreport.validated = JSV.clone(report.validated);
  2374. if (key.validate(instance, subreport, parent, parentSchema, name).errors.length === 0) {
  2375. //instance matches this schema
  2376. report.addError(instance, schema, "disallow", "Instance is a disallowed type", disallowedTypes);
  2377. return false;
  2378. }
  2379. } else if (typeValidators[key] !== O[key] && typeof typeValidators[key] === "function") {
  2380. if (typeValidators[key](instance, report)) {
  2381. report.addError(instance, schema, "disallow", "Instance is a disallowed type", disallowedTypes);
  2382. return false;
  2383. }
  2384. }
  2385. /*
  2386. else {
  2387. report.addError(instance, schema, "disallow", "Instance may be a disallowed type", disallowedTypes);
  2388. return false;
  2389. }
  2390. */
  2391. }
  2392. //if we get to this point, type is valid
  2393. return true;
  2394. }
  2395. //else, everything is allowed if no disallowed types are specified
  2396. return true;
  2397. },
  2398. "typeValidators" : TYPE_VALIDATORS
  2399. },
  2400. "extends" : {
  2401. "type" : [{"$ref" : "#"}, "array"],
  2402. "items" : {"$ref" : "#"},
  2403. "optional" : true,
  2404. "default" : {},
  2405. "parser" : function (instance, self) {
  2406. if (instance.getType() === "object") {
  2407. return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  2408. } else if (instance.getType() === "array") {
  2409. return JSV.mapArray(instance.getProperties(), function (instance) {
  2410. return instance.getEnvironment().createSchema(instance, self.getEnvironment().findSchema(self.resolveURI("#")));
  2411. });
  2412. }
  2413. },
  2414. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2415. var extensions = schema.getAttribute("extends"), x, xl;
  2416. if (extensions) {
  2417. if (JSV.isJSONSchema(extensions)) {
  2418. extensions.validate(instance, report, parent, parentSchema, name);
  2419. } else if (JSV.typeOf(extensions) === "array") {
  2420. for (x = 0, xl = extensions.length; x < xl; ++x) {
  2421. extensions[x].validate(instance, report, parent, parentSchema, name);
  2422. }
  2423. }
  2424. }
  2425. }
  2426. }
  2427. },
  2428. "optional" : true,
  2429. "default" : {},
  2430. "fragmentResolution" : "dot-delimited",
  2431. "parser" : function (instance, self) {
  2432. if (instance.getType() === "object") {
  2433. return instance.getEnvironment().createSchema(instance, self);
  2434. }
  2435. },
  2436. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2437. var propNames = schema.getPropertyNames(),
  2438. x, xl,
  2439. attributeSchemas = self.getAttribute("properties"),
  2440. strict = instance.getEnvironment().getOption("strict"),
  2441. validator;
  2442. for (x in attributeSchemas) {
  2443. if (attributeSchemas[x] !== O[x]) {
  2444. if (attributeSchemas[x].getValueOfProperty("validationRequired")) {
  2445. JSV.pushUnique(propNames, x);
  2446. }
  2447. if (strict && attributeSchemas[x].getValueOfProperty("deprecated")) {
  2448. JSV.popFirst(propNames, x);
  2449. }
  2450. }
  2451. }
  2452. for (x = 0, xl = propNames.length; x < xl; ++x) {
  2453. if (attributeSchemas[propNames[x]] !== O[propNames[x]]) {
  2454. validator = attributeSchemas[propNames[x]].getValueOfProperty("validator");
  2455. if (typeof validator === "function") {
  2456. validator(instance, schema, attributeSchemas[propNames[x]], report, parent, parentSchema, name);
  2457. }
  2458. }
  2459. }
  2460. }
  2461. };
  2462. HYPERSCHEMA_00_JSON = {
  2463. "$schema" : "http://json-schema.org/draft-00/hyper-schema#",
  2464. "id" : "http://json-schema.org/draft-00/hyper-schema#",
  2465. "properties" : {
  2466. "links" : {
  2467. "type" : "array",
  2468. "items" : {"$ref" : "links#"},
  2469. "optional" : true,
  2470. "parser" : function (instance, self, arg) {
  2471. var links,
  2472. linkSchemaURI = self.getValueOfProperty("items")["$ref"],
  2473. linkSchema = self.getEnvironment().findSchema(linkSchemaURI),
  2474. linkParser = linkSchema && linkSchema.getValueOfProperty("parser"),
  2475. selfReferenceVariable;
  2476. arg = JSV.toArray(arg);
  2477. if (typeof linkParser === "function") {
  2478. links = JSV.mapArray(instance.getProperties(), function (link) {
  2479. return linkParser(link, linkSchema);
  2480. });
  2481. } else {
  2482. links = JSV.toArray(instance.getValue());
  2483. }
  2484. if (arg[0]) {
  2485. links = JSV.filterArray(links, function (link) {
  2486. return link["rel"] === arg[0];
  2487. });
  2488. }
  2489. if (arg[1]) {
  2490. selfReferenceVariable = self.getValueOfProperty("selfReferenceVariable");
  2491. links = JSV.mapArray(links, function (link) {
  2492. var instance = arg[1],
  2493. href = link["href"];
  2494. href = href.replace(/\{(.+)\}/g, function (str, p1, offset, s) {
  2495. var value;
  2496. if (p1 === selfReferenceVariable) {
  2497. value = instance.getValue();
  2498. } else {
  2499. value = instance.getValueOfProperty(p1);
  2500. }
  2501. return value !== undefined ? String(value) : "";
  2502. });
  2503. return href ? JSV.formatURI(instance.resolveURI(href)) : href;
  2504. });
  2505. }
  2506. return links;
  2507. },
  2508. "selfReferenceVariable" : "-this"
  2509. },
  2510. "fragmentResolution" : {
  2511. "type" : "string",
  2512. "optional" : true,
  2513. "default" : "dot-delimited"
  2514. },
  2515. "root" : {
  2516. "type" : "boolean",
  2517. "optional" : true,
  2518. "default" : false
  2519. },
  2520. "readonly" : {
  2521. "type" : "boolean",
  2522. "optional" : true,
  2523. "default" : false
  2524. },
  2525. "pathStart" : {
  2526. "type" : "string",
  2527. "optional" : true,
  2528. "format" : "uri",
  2529. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2530. var pathStart;
  2531. if (instance.getType() !== "undefined") {
  2532. pathStart = schema.getAttribute("pathStart");
  2533. if (typeof pathStart === "string") {
  2534. //TODO: Find out what pathStart is relative to
  2535. if (instance.getURI().indexOf(pathStart) !== 0) {
  2536. report.addError(instance, schema, "pathStart", "Instance's URI does not start with " + pathStart, pathStart);
  2537. }
  2538. }
  2539. }
  2540. }
  2541. },
  2542. "mediaType" : {
  2543. "type" : "string",
  2544. "optional" : true,
  2545. "format" : "media-type"
  2546. },
  2547. "alternate" : {
  2548. "type" : "array",
  2549. "items" : {"$ref" : "#"},
  2550. "optional" : true
  2551. }
  2552. },
  2553. "links" : [
  2554. {
  2555. "href" : "{$ref}",
  2556. "rel" : "full"
  2557. },
  2558. {
  2559. "href" : "{$schema}",
  2560. "rel" : "describedby"
  2561. },
  2562. {
  2563. "href" : "{id}",
  2564. "rel" : "self"
  2565. }
  2566. ],
  2567. "initializer" : function (instance) {
  2568. var link, extension, extended;
  2569. //if there is a link to a different schema, update instance
  2570. link = instance._schema.getLink("describedby", instance);
  2571. if (link && instance._schema._uri !== link) {
  2572. if (instance._env._schemas[link]) {
  2573. instance._schema = instance._env._schemas[link];
  2574. initializer = instance._schema.getValueOfProperty("initializer");
  2575. if (typeof initializer === "function") {
  2576. return initializer(instance); //this function will finish initialization
  2577. } else {
  2578. return instance; //no further initialization
  2579. }
  2580. } else if (instance._env._options["validateReferences"]) {
  2581. throw new InitializationError(instance, instance._schema, "{link:describedby}", "Unknown schema reference", link);
  2582. }
  2583. }
  2584. //if there is a link to the full representation, replace instance
  2585. link = instance._schema.getLink("full", instance);
  2586. if (link && instance._uri !== link) {
  2587. if (instance._env._schemas[link]) {
  2588. instance = instance._env._schemas[link];
  2589. return instance; //retrieved schemas are guaranteed to be initialized
  2590. } else if (instance._env._options["validateReferences"]) {
  2591. throw new InitializationError(instance, instance._schema, "{link:full}", "Unknown schema reference", link);
  2592. }
  2593. }
  2594. //extend schema
  2595. extension = instance.getAttribute("extends");
  2596. if (JSV.isJSONSchema(extension)) {
  2597. extended = JSV.inherits(extension, instance, true);
  2598. instance = instance._env.createSchema(extended, instance._schema, instance._uri);
  2599. }
  2600. //if instance has a URI link to itself, update it's own URI
  2601. link = instance._schema.getLink("self", instance);
  2602. if (JSV.typeOf(link) === "string") {
  2603. instance._uri = JSV.formatURI(link);
  2604. }
  2605. return instance;
  2606. }
  2607. //not needed as JSV.inherits does the job for us
  2608. //"extends" : {"$ref" : "http://json-schema.org/schema#"}
  2609. };
  2610. LINKS_00_JSON = {
  2611. "$schema" : "http://json-schema.org/draft-00/hyper-schema#",
  2612. "id" : "http://json-schema.org/draft-00/links#",
  2613. "type" : "object",
  2614. "properties" : {
  2615. "href" : {
  2616. "type" : "string"
  2617. },
  2618. "rel" : {
  2619. "type" : "string"
  2620. },
  2621. "method" : {
  2622. "type" : "string",
  2623. "default" : "GET",
  2624. "optional" : true
  2625. },
  2626. "enctype" : {
  2627. "type" : "string",
  2628. "requires" : "method",
  2629. "optional" : true
  2630. },
  2631. "properties" : {
  2632. "type" : "object",
  2633. "additionalProperties" : {"$ref" : "hyper-schema#"},
  2634. "optional" : true,
  2635. "parser" : function (instance, self, arg) {
  2636. var env = instance.getEnvironment(),
  2637. selfEnv = self.getEnvironment(),
  2638. additionalPropertiesSchemaURI = self.getValueOfProperty("additionalProperties")["$ref"];
  2639. if (instance.getType() === "object") {
  2640. if (arg) {
  2641. return env.createSchema(instance.getProperty(arg), selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
  2642. } else {
  2643. return JSV.mapObject(instance.getProperties(), function (instance) {
  2644. return env.createSchema(instance, selfEnv.findSchema(self.resolveURI(additionalPropertiesSchemaURI)));
  2645. });
  2646. }
  2647. }
  2648. }
  2649. }
  2650. },
  2651. "parser" : function (instance, self) {
  2652. var selfProperties = self.getProperty("properties");
  2653. if (instance.getType() === "object") {
  2654. return JSV.mapObject(instance.getProperties(), function (property, key) {
  2655. var propertySchema = selfProperties.getProperty(key),
  2656. parser = propertySchema && propertySchema.getValueOfProperty("parser");
  2657. if (typeof parser === "function") {
  2658. return parser(property, propertySchema);
  2659. }
  2660. //else
  2661. return property.getValue();
  2662. });
  2663. }
  2664. return instance.getValue();
  2665. }
  2666. };
  2667. ENVIRONMENT.setOption("defaultFragmentDelimiter", ".");
  2668. ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-00/schema#"); //updated later
  2669. SCHEMA_00 = ENVIRONMENT.createSchema(SCHEMA_00_JSON, true, "http://json-schema.org/draft-00/schema#");
  2670. HYPERSCHEMA_00 = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA_00, ENVIRONMENT.createSchema(HYPERSCHEMA_00_JSON, true, "http://json-schema.org/draft-00/hyper-schema#"), true), true, "http://json-schema.org/draft-00/hyper-schema#");
  2671. ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-00/hyper-schema#");
  2672. LINKS_00 = ENVIRONMENT.createSchema(LINKS_00_JSON, HYPERSCHEMA_00, "http://json-schema.org/draft-00/links#");
  2673. //We need to reinitialize these 3 schemas as they all reference each other
  2674. SCHEMA_00 = ENVIRONMENT.createSchema(SCHEMA_00.getValue(), HYPERSCHEMA_00, "http://json-schema.org/draft-00/schema#");
  2675. HYPERSCHEMA_00 = ENVIRONMENT.createSchema(HYPERSCHEMA_00.getValue(), HYPERSCHEMA_00, "http://json-schema.org/draft-00/hyper-schema#");
  2676. LINKS_00 = ENVIRONMENT.createSchema(LINKS_00.getValue(), HYPERSCHEMA_00, "http://json-schema.org/draft-00/links#");
  2677. //
  2678. // draft-01
  2679. //
  2680. SCHEMA_01_JSON = JSV.inherits(SCHEMA_00_JSON, {
  2681. "$schema" : "http://json-schema.org/draft-01/hyper-schema#",
  2682. "id" : "http://json-schema.org/draft-01/schema#"
  2683. });
  2684. HYPERSCHEMA_01_JSON = JSV.inherits(HYPERSCHEMA_00_JSON, {
  2685. "$schema" : "http://json-schema.org/draft-01/hyper-schema#",
  2686. "id" : "http://json-schema.org/draft-01/hyper-schema#"
  2687. });
  2688. LINKS_01_JSON = JSV.inherits(LINKS_00_JSON, {
  2689. "$schema" : "http://json-schema.org/draft-01/hyper-schema#",
  2690. "id" : "http://json-schema.org/draft-01/links#"
  2691. });
  2692. ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-01/schema#"); //update later
  2693. SCHEMA_01 = ENVIRONMENT.createSchema(SCHEMA_01_JSON, true, "http://json-schema.org/draft-01/schema#");
  2694. HYPERSCHEMA_01 = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA_01, ENVIRONMENT.createSchema(HYPERSCHEMA_01_JSON, true, "http://json-schema.org/draft-01/hyper-schema#"), true), true, "http://json-schema.org/draft-01/hyper-schema#");
  2695. ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-01/hyper-schema#");
  2696. LINKS_01 = ENVIRONMENT.createSchema(LINKS_01_JSON, HYPERSCHEMA_01, "http://json-schema.org/draft-01/links#");
  2697. //We need to reinitialize these 3 schemas as they all reference each other
  2698. SCHEMA_01 = ENVIRONMENT.createSchema(SCHEMA_01.getValue(), HYPERSCHEMA_01, "http://json-schema.org/draft-01/schema#");
  2699. HYPERSCHEMA_01 = ENVIRONMENT.createSchema(HYPERSCHEMA_01.getValue(), HYPERSCHEMA_01, "http://json-schema.org/draft-01/hyper-schema#");
  2700. LINKS_01 = ENVIRONMENT.createSchema(LINKS_01.getValue(), HYPERSCHEMA_01, "http://json-schema.org/draft-01/links#");
  2701. //
  2702. // draft-02
  2703. //
  2704. SCHEMA_02_JSON = JSV.inherits(SCHEMA_01_JSON, {
  2705. "$schema" : "http://json-schema.org/draft-02/hyper-schema#",
  2706. "id" : "http://json-schema.org/draft-02/schema#",
  2707. "properties" : {
  2708. "uniqueItems" : {
  2709. "type" : "boolean",
  2710. "optional" : true,
  2711. "default" : false,
  2712. "parser" : function (instance, self) {
  2713. return !!instance.getValue();
  2714. },
  2715. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2716. var value, x, xl, y, yl;
  2717. if (instance.getType() === "array" && schema.getAttribute("uniqueItems")) {
  2718. value = instance.getProperties();
  2719. for (x = 0, xl = value.length - 1; x < xl; ++x) {
  2720. for (y = x + 1, yl = value.length; y < yl; ++y) {
  2721. if (value[x].equals(value[y])) {
  2722. report.addError(instance, schema, "uniqueItems", "Array can only contain unique items", { x : x, y : y });
  2723. }
  2724. }
  2725. }
  2726. }
  2727. }
  2728. },
  2729. "maxDecimal" : {
  2730. "deprecated" : true
  2731. },
  2732. "divisibleBy" : {
  2733. "type" : "number",
  2734. "minimum" : 0,
  2735. "minimumCanEqual" : false,
  2736. "optional" : true,
  2737. "parser" : function (instance, self) {
  2738. if (instance.getType() === "number") {
  2739. return instance.getValue();
  2740. }
  2741. },
  2742. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2743. var divisor;
  2744. if (instance.getType() === "number") {
  2745. divisor = schema.getAttribute("divisibleBy");
  2746. if (divisor === 0) {
  2747. report.addError(instance, schema, "divisibleBy", "Nothing is divisible by 0", divisor);
  2748. } else if (divisor !== 1 && ((instance.getValue() / divisor) % 1) !== 0) {
  2749. report.addError(instance, schema, "divisibleBy", "Number is not divisible by " + divisor, divisor);
  2750. }
  2751. }
  2752. }
  2753. }
  2754. },
  2755. "fragmentResolution" : "slash-delimited"
  2756. });
  2757. HYPERSCHEMA_02_JSON = JSV.inherits(HYPERSCHEMA_01_JSON, {
  2758. "id" : "http://json-schema.org/draft-02/hyper-schema#",
  2759. "properties" : {
  2760. "fragmentResolution" : {
  2761. "default" : "slash-delimited"
  2762. }
  2763. }
  2764. });
  2765. LINKS_02_JSON = JSV.inherits(LINKS_01_JSON, {
  2766. "$schema" : "http://json-schema.org/draft-02/hyper-schema#",
  2767. "id" : "http://json-schema.org/draft-02/links#",
  2768. "properties" : {
  2769. "targetSchema" : {
  2770. "$ref" : "hyper-schema#",
  2771. //need this here because parsers are run before links are resolved
  2772. "parser" : HYPERSCHEMA_01.getAttribute("parser")
  2773. }
  2774. }
  2775. });
  2776. ENVIRONMENT.setOption("defaultFragmentDelimiter", "/");
  2777. ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-02/schema#"); //update later
  2778. SCHEMA_02 = ENVIRONMENT.createSchema(SCHEMA_02_JSON, true, "http://json-schema.org/draft-02/schema#");
  2779. HYPERSCHEMA_02 = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA_02, ENVIRONMENT.createSchema(HYPERSCHEMA_02_JSON, true, "http://json-schema.org/draft-02/hyper-schema#"), true), true, "http://json-schema.org/draft-02/hyper-schema#");
  2780. ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-02/hyper-schema#");
  2781. LINKS_02 = ENVIRONMENT.createSchema(LINKS_02_JSON, HYPERSCHEMA_02, "http://json-schema.org/draft-02/links#");
  2782. //We need to reinitialize these 3 schemas as they all reference each other
  2783. SCHEMA_02 = ENVIRONMENT.createSchema(SCHEMA_02.getValue(), HYPERSCHEMA_02, "http://json-schema.org/draft-02/schema#");
  2784. HYPERSCHEMA_02 = ENVIRONMENT.createSchema(HYPERSCHEMA_02.getValue(), HYPERSCHEMA_02, "http://json-schema.org/draft-02/hyper-schema#");
  2785. LINKS_02 = ENVIRONMENT.createSchema(LINKS_02.getValue(), HYPERSCHEMA_02, "http://json-schema.org/draft-02/links#");
  2786. //
  2787. // draft-03
  2788. //
  2789. function getMatchedPatternProperties(instance, schema, report, self) {
  2790. var matchedProperties = {}, patternProperties, pattern, regexp, properties, key;
  2791. if (instance.getType() === "object") {
  2792. patternProperties = schema.getAttribute("patternProperties");
  2793. properties = instance.getProperties();
  2794. for (pattern in patternProperties) {
  2795. if (patternProperties[pattern] !== O[pattern]) {
  2796. regexp = null;
  2797. try {
  2798. regexp = new RegExp(pattern);
  2799. } catch (e) {
  2800. if (report) {
  2801. report.addError(schema, self, "patternProperties", "Invalid pattern", pattern);
  2802. }
  2803. }
  2804. if (regexp) {
  2805. for (key in properties) {
  2806. if (properties[key] !== O[key] && regexp.test(key)) {
  2807. matchedProperties[key] = matchedProperties[key] ? JSV.pushUnique(matchedProperties[key], patternProperties[pattern]) : [ patternProperties[pattern] ];
  2808. }
  2809. }
  2810. }
  2811. }
  2812. }
  2813. }
  2814. return matchedProperties;
  2815. }
  2816. SCHEMA_03_JSON = JSV.inherits(SCHEMA_02_JSON, {
  2817. "$schema" : "http://json-schema.org/draft-03/schema#",
  2818. "id" : "http://json-schema.org/draft-03/schema#",
  2819. "properties" : {
  2820. "patternProperties" : {
  2821. "type" : "object",
  2822. "additionalProperties" : {"$ref" : "#"},
  2823. "default" : {},
  2824. "parser" : SCHEMA_02.getValueOfProperty("properties")["properties"]["parser"],
  2825. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2826. var matchedProperties, key, x;
  2827. if (instance.getType() === "object") {
  2828. matchedProperties = getMatchedPatternProperties(instance, schema, report, self);
  2829. for (key in matchedProperties) {
  2830. if (matchedProperties[key] !== O[key]) {
  2831. x = matchedProperties[key].length;
  2832. while (x--) {
  2833. matchedProperties[key][x].validate(instance.getProperty(key), report, instance, schema, key);
  2834. }
  2835. }
  2836. }
  2837. }
  2838. }
  2839. },
  2840. "additionalProperties" : {
  2841. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2842. var additionalProperties, propertySchemas, properties, matchedProperties, key;
  2843. if (instance.getType() === "object") {
  2844. additionalProperties = schema.getAttribute("additionalProperties");
  2845. propertySchemas = schema.getAttribute("properties") || {};
  2846. properties = instance.getProperties();
  2847. matchedProperties = getMatchedPatternProperties(instance, schema);
  2848. for (key in properties) {
  2849. if (properties[key] !== O[key] && properties[key] && propertySchemas[key] === O[key] && matchedProperties[key] === O[key]) {
  2850. if (JSV.isJSONSchema(additionalProperties)) {
  2851. additionalProperties.validate(properties[key], report, instance, schema, key);
  2852. } else if (additionalProperties === false) {
  2853. report.addError(instance, schema, "additionalProperties", "Additional properties are not allowed", additionalProperties);
  2854. }
  2855. }
  2856. }
  2857. }
  2858. }
  2859. },
  2860. "items" : {
  2861. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2862. var properties, items, x, xl, itemSchema, additionalItems;
  2863. if (instance.getType() === "array") {
  2864. properties = instance.getProperties();
  2865. items = schema.getAttribute("items");
  2866. additionalItems = schema.getAttribute("additionalItems");
  2867. if (JSV.typeOf(items) === "array") {
  2868. for (x = 0, xl = properties.length; x < xl; ++x) {
  2869. itemSchema = items[x] || additionalItems;
  2870. if (itemSchema !== false) {
  2871. itemSchema.validate(properties[x], report, instance, schema, x);
  2872. } else {
  2873. report.addError(instance, schema, "additionalItems", "Additional items are not allowed", itemSchema);
  2874. }
  2875. }
  2876. } else {
  2877. itemSchema = items || additionalItems;
  2878. for (x = 0, xl = properties.length; x < xl; ++x) {
  2879. itemSchema.validate(properties[x], report, instance, schema, x);
  2880. }
  2881. }
  2882. }
  2883. }
  2884. },
  2885. "additionalItems" : {
  2886. "type" : [{"$ref" : "#"}, "boolean"],
  2887. "default" : {},
  2888. "parser" : SCHEMA_02.getValueOfProperty("properties")["additionalProperties"]["parser"],
  2889. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2890. var additionalItems, properties, x, xl;
  2891. //only validate if the "items" attribute is undefined
  2892. if (instance.getType() === "array" && schema.getProperty("items").getType() === "undefined") {
  2893. additionalItems = schema.getAttribute("additionalItems");
  2894. properties = instance.getProperties();
  2895. if (additionalItems !== false) {
  2896. for (x = 0, xl = properties.length; x < xl; ++x) {
  2897. additionalItems.validate(properties[x], report, instance, schema, x);
  2898. }
  2899. } else if (properties.length) {
  2900. report.addError(instance, schema, "additionalItems", "Additional items are not allowed", additionalItems);
  2901. }
  2902. }
  2903. }
  2904. },
  2905. "optional" : {
  2906. "validationRequired" : false,
  2907. "deprecated" : true
  2908. },
  2909. "required" : {
  2910. "type" : "boolean",
  2911. "default" : false,
  2912. "parser" : function (instance, self) {
  2913. return !!instance.getValue();
  2914. },
  2915. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2916. if (instance.getType() === "undefined" && schema.getAttribute("required")) {
  2917. report.addError(instance, schema, "required", "Property is required", true);
  2918. }
  2919. }
  2920. },
  2921. "requires" : {
  2922. "deprecated" : true
  2923. },
  2924. "dependencies" : {
  2925. "type" : "object",
  2926. "additionalProperties" : {
  2927. "type" : ["string", "array", {"$ref" : "#"}],
  2928. "items" : {
  2929. "type" : "string"
  2930. }
  2931. },
  2932. "default" : {},
  2933. "parser" : function (instance, self, arg) {
  2934. function parseProperty(property) {
  2935. var type = property.getType();
  2936. if (type === "string" || type === "array") {
  2937. return property.getValue();
  2938. } else if (type === "object") {
  2939. return property.getEnvironment().createSchema(property, self.getEnvironment().findSchema(self.resolveURI("#")));
  2940. }
  2941. }
  2942. if (instance.getType() === "object") {
  2943. if (arg) {
  2944. return parseProperty(instance.getProperty(arg));
  2945. } else {
  2946. return JSV.mapObject(instance.getProperties(), parseProperty);
  2947. }
  2948. }
  2949. //else
  2950. return {};
  2951. },
  2952. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  2953. var dependencies, key, dependency, type, x, xl;
  2954. if (instance.getType() === "object") {
  2955. dependencies = schema.getAttribute("dependencies");
  2956. for (key in dependencies) {
  2957. if (dependencies[key] !== O[key] && instance.getProperty(key).getType() !== "undefined") {
  2958. dependency = dependencies[key];
  2959. type = JSV.typeOf(dependency);
  2960. if (type === "string") {
  2961. if (instance.getProperty(dependency).getType() === "undefined") {
  2962. report.addError(instance, schema, "dependencies", 'Property "' + key + '" requires sibling property "' + dependency + '"', dependencies);
  2963. }
  2964. } else if (type === "array") {
  2965. for (x = 0, xl = dependency.length; x < xl; ++x) {
  2966. if (instance.getProperty(dependency[x]).getType() === "undefined") {
  2967. report.addError(instance, schema, "dependencies", 'Property "' + key + '" requires sibling property "' + dependency[x] + '"', dependencies);
  2968. }
  2969. }
  2970. } else if (JSV.isJSONSchema(dependency)) {
  2971. dependency.validate(instance, report);
  2972. }
  2973. }
  2974. }
  2975. }
  2976. }
  2977. },
  2978. "minimumCanEqual" : {
  2979. "deprecated" : true
  2980. },
  2981. "maximumCanEqual" : {
  2982. "deprecated" : true
  2983. },
  2984. "exclusiveMinimum" : {
  2985. "type" : "boolean",
  2986. "default" : false,
  2987. "parser" : function (instance, self) {
  2988. return !!instance.getValue();
  2989. }
  2990. },
  2991. "exclusiveMaximum" : {
  2992. "type" : "boolean",
  2993. "default" : false,
  2994. "parser" : function (instance, self) {
  2995. return !!instance.getValue();
  2996. }
  2997. },
  2998. "minimum" : {
  2999. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  3000. var minimum, exclusiveMinimum;
  3001. if (instance.getType() === "number") {
  3002. minimum = schema.getAttribute("minimum");
  3003. exclusiveMinimum = schema.getAttribute("exclusiveMinimum") || (!instance.getEnvironment().getOption("strict") && !schema.getAttribute("minimumCanEqual"));
  3004. if (typeof minimum === "number" && (instance.getValue() < minimum || (exclusiveMinimum === true && instance.getValue() === minimum))) {
  3005. report.addError(instance, schema, "minimum", "Number is less then the required minimum value", minimum);
  3006. }
  3007. }
  3008. }
  3009. },
  3010. "maximum" : {
  3011. "validator" : function (instance, schema, self, report, parent, parentSchema, name) {
  3012. var maximum, exclusiveMaximum;
  3013. if (instance.getType() === "number") {
  3014. maximum = schema.getAttribute("maximum");
  3015. exclusiveMaximum = schema.getAttribute("exclusiveMaximum") || (!instance.getEnvironment().getOption("strict") && !schema.getAttribute("maximumCanEqual"));
  3016. if (typeof maximum === "number" && (instance.getValue() > maximum || (exclusiveMaximum === true && instance.getValue() === maximum))) {
  3017. report.addError(instance, schema, "maximum", "Number is greater then the required maximum value", maximum);
  3018. }
  3019. }
  3020. }
  3021. },
  3022. "contentEncoding" : {
  3023. "deprecated" : true
  3024. },
  3025. "divisibleBy" : {
  3026. "exclusiveMinimum" : true
  3027. },
  3028. "disallow" : {
  3029. "items" : {
  3030. "type" : ["string", {"$ref" : "#"}]
  3031. },
  3032. "parser" : SCHEMA_02_JSON["properties"]["type"]["parser"]
  3033. },
  3034. "id" : {
  3035. "type" : "string",
  3036. "format" : "uri"
  3037. },
  3038. "$ref" : {
  3039. "type" : "string",
  3040. "format" : "uri"
  3041. },
  3042. "$schema" : {
  3043. "type" : "string",
  3044. "format" : "uri"
  3045. }
  3046. },
  3047. "dependencies" : {
  3048. "exclusiveMinimum" : "minimum",
  3049. "exclusiveMaximum" : "maximum"
  3050. },
  3051. "initializer" : function (instance) {
  3052. var link, extension, extended,
  3053. schemaLink = instance.getValueOfProperty("$schema"),
  3054. refLink = instance.getValueOfProperty("$ref"),
  3055. idLink = instance.getValueOfProperty("id");
  3056. //if there is a link to a different schema, update instance
  3057. if (schemaLink) {
  3058. link = instance.resolveURI(schemaLink);
  3059. if (link && instance._schema._uri !== link) {
  3060. if (instance._env._schemas[link]) {
  3061. instance._schema = instance._env._schemas[link];
  3062. initializer = instance._schema.getValueOfProperty("initializer");
  3063. if (typeof initializer === "function") {
  3064. return initializer(instance); //this function will finish initialization
  3065. } else {
  3066. return instance; //no further initialization
  3067. }
  3068. } else if (instance._env._options["validateReferences"]) {
  3069. throw new InitializationError(instance, instance._schema, "$schema", "Unknown schema reference", link);
  3070. }
  3071. }
  3072. }
  3073. //if there is a link to the full representation, replace instance
  3074. if (refLink) {
  3075. link = instance.resolveURI(refLink);
  3076. if (link && instance._uri !== link) {
  3077. if (instance._env._schemas[link]) {
  3078. instance = instance._env._schemas[link];
  3079. return instance; //retrieved schemas are guaranteed to be initialized
  3080. } else if (instance._env._options["validateReferences"]) {
  3081. throw new InitializationError(instance, instance._schema, "$ref", "Unknown schema reference", link);
  3082. }
  3083. }
  3084. }
  3085. //extend schema
  3086. extension = instance.getAttribute("extends");
  3087. if (JSV.isJSONSchema(extension)) {
  3088. extended = JSV.inherits(extension, instance, true);
  3089. instance = instance._env.createSchema(extended, instance._schema, instance._uri);
  3090. }
  3091. //if instance has a URI link to itself, update it's own URI
  3092. if (idLink) {
  3093. link = instance.resolveURI(idLink);
  3094. if (JSV.typeOf(link) === "string") {
  3095. instance._uri = JSV.formatURI(link);
  3096. }
  3097. }
  3098. return instance;
  3099. }
  3100. });
  3101. HYPERSCHEMA_03_JSON = JSV.inherits(HYPERSCHEMA_02_JSON, {
  3102. "$schema" : "http://json-schema.org/draft-03/hyper-schema#",
  3103. "id" : "http://json-schema.org/draft-03/hyper-schema#",
  3104. "properties" : {
  3105. "links" : {
  3106. "selfReferenceVariable" : "@"
  3107. },
  3108. "root" : {
  3109. "deprecated" : true
  3110. },
  3111. "contentEncoding" : {
  3112. "deprecated" : false //moved from core to hyper
  3113. },
  3114. "alternate" : {
  3115. "deprecated" : true
  3116. }
  3117. }
  3118. });
  3119. LINKS_03_JSON = JSV.inherits(LINKS_02_JSON, {
  3120. "$schema" : "http://json-schema.org/draft-03/hyper-schema#",
  3121. "id" : "http://json-schema.org/draft-03/links#",
  3122. "properties" : {
  3123. "href" : {
  3124. "required" : true,
  3125. "format" : "link-description-object-template"
  3126. },
  3127. "rel" : {
  3128. "required" : true
  3129. },
  3130. "properties" : {
  3131. "deprecated" : true
  3132. },
  3133. "schema" : {"$ref" : "http://json-schema.org/draft-03/hyper-schema#"}
  3134. }
  3135. });
  3136. ENVIRONMENT.setOption("validateReferences", true);
  3137. ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-03/schema#"); //update later
  3138. //prevent reference errors
  3139. ENVIRONMENT.createSchema({}, true, "http://json-schema.org/draft-03/schema#");
  3140. ENVIRONMENT.createSchema({}, true, "http://json-schema.org/draft-03/hyper-schema#");
  3141. ENVIRONMENT.createSchema({}, true, "http://json-schema.org/draft-03/links#");
  3142. SCHEMA_03 = ENVIRONMENT.createSchema(SCHEMA_03_JSON, true, "http://json-schema.org/draft-03/schema#");
  3143. HYPERSCHEMA_03 = ENVIRONMENT.createSchema(JSV.inherits(SCHEMA_03, ENVIRONMENT.createSchema(HYPERSCHEMA_03_JSON, true, "http://json-schema.org/draft-03/hyper-schema#"), true), true, "http://json-schema.org/draft-03/hyper-schema#");
  3144. LINKS_03 = ENVIRONMENT.createSchema(LINKS_03_JSON, true, "http://json-schema.org/draft-03/links#");
  3145. ENVIRONMENT.setOption("defaultSchemaURI", "http://json-schema.org/draft-03/hyper-schema#");
  3146. //We need to reinitialize these schemas as they reference each other
  3147. HYPERSCHEMA_03 = ENVIRONMENT.createSchema(HYPERSCHEMA_03.getValue(), HYPERSCHEMA_03, "http://json-schema.org/draft-03/hyper-schema#");
  3148. ENVIRONMENT.setOption("latestJSONSchemaSchemaURI", "http://json-schema.org/draft-03/schema#");
  3149. ENVIRONMENT.setOption("latestJSONSchemaHyperSchemaURI", "http://json-schema.org/draft-03/hyper-schema#");
  3150. ENVIRONMENT.setOption("latestJSONSchemaLinksURI", "http://json-schema.org/draft-03/links#");
  3151. //
  3152. //Latest JSON Schema
  3153. //
  3154. //Hack, but WAY faster then instantiating a new schema
  3155. ENVIRONMENT._schemas["http://json-schema.org/schema#"] = SCHEMA_03;
  3156. ENVIRONMENT._schemas["http://json-schema.org/hyper-schema#"] = HYPERSCHEMA_03;
  3157. ENVIRONMENT._schemas["http://json-schema.org/links#"] = LINKS_03;
  3158. //
  3159. //register environment
  3160. //
  3161. JSV.registerEnvironment("json-schema-draft-03", ENVIRONMENT);
  3162. if (!JSV.getDefaultEnvironmentID() || JSV.getDefaultEnvironmentID() === "json-schema-draft-01" || JSV.getDefaultEnvironmentID() === "json-schema-draft-02") {
  3163. JSV.setDefaultEnvironmentID("json-schema-draft-03");
  3164. }
  3165. }());
  3166. global.JSONFormValidator = exports.JSV;
  3167. })(this, false);