parse.js 104 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889
  1. var Node = require('../node');
  2. var NodeType = require('../node-types');
  3. var TokenType = require('../token-types');
  4. module.exports = (function() {
  5. var tokens, tokensLength, pos, needInfo;
  6. var rules = {
  7. 'arguments': function() { return checkArguments(pos) && getArguments(); },
  8. 'atkeyword': function() { return checkAtkeyword(pos) && getAtkeyword(); },
  9. 'atruleb': function() { return checkAtruleb(pos) && getAtruleb(); },
  10. 'atruler': function() { return checkAtruler(pos) && getAtruler(); },
  11. 'atrulerq': function() { return checkAtrulerq(pos) && getAtrulerq(); },
  12. 'atrulers': function() { return checkAtrulers(pos) && getAtrulers(); },
  13. 'atrules': function() { return checkAtrules(pos) && getAtrules(); },
  14. 'attrib': function() { return checkAttrib(pos) && getAttrib(); },
  15. 'attrselector': function() { return checkAttrselector(pos) && getAttrselector(); },
  16. 'block': function() { return checkBlock(pos) && getBlock(); },
  17. 'braces': function() { return checkBraces(pos) && getBraces(); },
  18. 'class': function() { return checkClass(pos) && getClass(); },
  19. 'combinator': function() { return checkCombinator(pos) && getCombinator(); },
  20. 'commentML': function() { return checkCommentML(pos) && getCommentML(); },
  21. 'commentSL': function() { return checkCommentSL(pos) && getCommentSL(); },
  22. 'condition': function() { return checkCondition(pos) && getCondition(); },
  23. 'conditionalStatement': function() { return checkConditionalStatement(pos) && getConditionalStatement(); },
  24. 'declaration': function() { return checkDeclaration(pos) && getDeclaration(); },
  25. 'declDelim': function() { return checkDeclDelim(pos) && getDeclDelim(); },
  26. 'default': function() { return checkDefault(pos) && getDefault(); },
  27. 'delim': function() { return checkDelim(pos) && getDelim(); },
  28. 'dimension': function() { return checkDimension(pos) && getDimension(); },
  29. 'filter': function() { return checkFilter(pos) && getFilter(); },
  30. 'filterv': function() { return checkFilterv(pos) && getFilterv(); },
  31. 'functionExpression': function() { return checkFunctionExpression(pos) && getFunctionExpression(); },
  32. 'function': function() { return checkFunction(pos) && getFunction(); },
  33. 'ident': function() { return checkIdent(pos) && getIdent(); },
  34. 'important': function() { return checkImportant(pos) && getImportant(); },
  35. 'include': function() { return checkInclude(pos) && getInclude(); },
  36. 'interpolation': function() { return checkInterpolation(pos) && getInterpolation(); },
  37. 'loop': function() { return checkLoop(pos) && getLoop(); },
  38. 'mixin': function() { return checkMixin(pos) && getMixin(); },
  39. 'namespace': function() { return checkNamespace(pos) && getNamespace(); },
  40. 'nth': function() { return checkNth(pos) && getNth(); },
  41. 'nthselector': function() { return checkNthselector(pos) && getNthselector(); },
  42. 'number': function() { return checkNumber(pos) && getNumber(); },
  43. 'operator': function() { return checkOperator(pos) && getOperator(); },
  44. 'parentselector': function() { return checkParentSelector(pos) && getParentSelector(); },
  45. 'percentage': function() { return checkPercentage(pos) && getPercentage(); },
  46. 'placeholder': function() { return checkPlaceholder(pos) && getPlaceholder(); },
  47. 'progid': function() { return checkProgid(pos) && getProgid(); },
  48. 'property': function() { return checkProperty(pos) && getProperty(); },
  49. 'propertyDelim': function() { return checkPropertyDelim(pos) && getPropertyDelim(); },
  50. 'pseudoc': function() { return checkPseudoc(pos) && getPseudoc(); },
  51. 'pseudoe': function() { return checkPseudoe(pos) && getPseudoe(); },
  52. 'ruleset': function() { return checkRuleset(pos) && getRuleset(); },
  53. 's': function() { return checkS(pos) && getS(); },
  54. 'selector': function() { return checkSelector(pos) && getSelector(); },
  55. 'shash': function() { return checkShash(pos) && getShash(); },
  56. 'simpleselector': function() { return checkSimpleSelector(pos) && getSimpleSelector(); },
  57. 'string': function() { return checkString(pos) && getString(); },
  58. 'stylesheet': function() { return checkStylesheet(pos) && getStylesheet(); },
  59. 'unary': function() { return checkUnary(pos) && getUnary(); },
  60. 'uri': function() { return checkUri(pos) && getUri(); },
  61. 'value': function() { return checkValue(pos) && getValue(); },
  62. 'variable': function () { return checkVariable(pos) && getVariable(); },
  63. 'variableslist': function () { return checkVariablesList(pos) && getVariablesList(); },
  64. 'vhash': function() { return checkVhash(pos) && getVhash(); }
  65. };
  66. /**
  67. * Stop parsing and display error
  68. * @param {Number=} i Token's index number
  69. */
  70. function throwError(i) {
  71. var ln = i ? tokens[i].ln : tokens[pos].ln;
  72. throw {line: ln, syntax: 'sass'};
  73. }
  74. /**
  75. * @param {Object} exclude
  76. * @param {Number} i Token's index number
  77. * @returns {Number}
  78. */
  79. function checkExcluding(exclude, i) {
  80. var start = i;
  81. while(i < tokensLength) {
  82. if (exclude[tokens[i++].type]) break;
  83. }
  84. return i - start - 2;
  85. }
  86. /**
  87. * @param {Number} start
  88. * @param {Number} finish
  89. * @returns {String}
  90. */
  91. function joinValues(start, finish) {
  92. var s = '';
  93. for (var i = start; i < finish + 1; i++) {
  94. s += tokens[i].value;
  95. }
  96. return s;
  97. }
  98. /**
  99. * @param {Number} start
  100. * @param {Number} num
  101. * @returns {String}
  102. */
  103. function joinValues2(start, num) {
  104. if (start + num - 1 >= tokensLength) return;
  105. var s = '';
  106. for (var i = 0; i < num; i++) {
  107. s += tokens[start + i].value;
  108. }
  109. return s;
  110. }
  111. /////////////////////////////////////
  112. /////////////////////////////////////
  113. /////////////////////////////////////
  114. /**
  115. * @param {Number} i Token's index number
  116. * @returns {Number}
  117. */
  118. function checkAny(i) {
  119. var l;
  120. if (l = checkBraces(i)) tokens[i].any_child = 1;
  121. else if (l = checkString(i)) tokens[i].any_child = 2;
  122. else if (l = checkVariablesList(i)) tokens[i].any_child = 3;
  123. else if (l = checkVariable(i)) tokens[i].any_child = 4;
  124. else if (l = checkPlaceholder(i)) tokens[i].any_child = 5;
  125. else if (l = checkPercentage(i)) tokens[i].any_child = 6;
  126. else if (l = checkDimension(i)) tokens[i].any_child = 7;
  127. else if (l = checkNumber(i)) tokens[i].any_child = 8;
  128. else if (l = checkUri(i)) tokens[i].any_child = 9;
  129. else if (l = checkFunctionExpression(i)) tokens[i].any_child = 10;
  130. else if (l = checkFunction(i)) tokens[i].any_child = 11;
  131. else if (l = checkIdent(i)) tokens[i].any_child = 12;
  132. else if (l = checkClass(i)) tokens[i].any_child = 13;
  133. else if (l = checkUnary(i)) tokens[i].any_child = 14;
  134. return l;
  135. }
  136. /**
  137. * @returns {Array}
  138. */
  139. function getAny() {
  140. var childType = tokens[pos].any_child;
  141. if (childType === 1) return getBraces();
  142. else if (childType === 2) return getString();
  143. else if (childType === 3) return getVariablesList();
  144. else if (childType === 4) return getVariable();
  145. else if (childType === 5) return getPlaceholder();
  146. else if (childType === 6) return getPercentage();
  147. else if (childType === 7) return getDimension();
  148. else if (childType === 8) return getNumber();
  149. else if (childType === 9) return getUri();
  150. else if (childType === 10) return getFunctionExpression();
  151. else if (childType === 11) return getFunction();
  152. else if (childType === 12) return getIdent();
  153. else if (childType === 13) return getClass();
  154. else if (childType === 14) return getUnary();
  155. }
  156. /**
  157. * Check if token is part of mixin's arguments.
  158. * @param {Number} i Token's index number
  159. * @returns {Number} Length of arguments
  160. */
  161. function checkArguments(i) {
  162. var start = i,
  163. l;
  164. if (i >= tokensLength ||
  165. tokens[i].type !== TokenType.LeftParenthesis) return 0;
  166. i++;
  167. while (i < tokens[start].right) {
  168. if (l = checkArgument(i)) i +=l;
  169. else return 0;
  170. }
  171. return tokens[start].right - start + 1;
  172. }
  173. /**
  174. * Check if token is valid to be part of arguments list
  175. * @param i Token's index number
  176. * @returns {Number} Length of argument
  177. */
  178. function checkArgument(i) {
  179. var l;
  180. if (l = checkBraces(i)) tokens[i].argument_child = 1;
  181. else if (l = checkDeclaration(i)) tokens[i].argument_child = 2;
  182. else if (l = checkFunction(i)) tokens[i].argument_child = 3;
  183. else if (l = checkVariablesList(i)) tokens[i].argument_child = 4;
  184. else if (l = checkVariable(i)) tokens[i].argument_child = 5;
  185. else if (l = checkSC(i)) tokens[i].argument_child = 6;
  186. else if (l = checkDelim(i)) tokens[i].argument_child = 7;
  187. else if (l = checkDeclDelim(i)) tokens[i].argument_child = 8;
  188. else if (l = checkString(i)) tokens[i].argument_child = 9;
  189. else if (l = checkPercentage(i)) tokens[i].argument_child = 10;
  190. else if (l = checkDimension(i)) tokens[i].argument_child = 11;
  191. else if (l = checkNumber(i)) tokens[i].argument_child = 12;
  192. else if (l = checkUri(i)) tokens[i].argument_child = 13;
  193. else if (l = checkInterpolation(i)) tokens[i].argument_child = 14;
  194. else if (l = checkIdent(i)) tokens[i].argument_child = 15;
  195. else if (l = checkVhash(i)) tokens[i].argument_child = 16;
  196. else if (l = checkOperator(i)) tokens[i].argument_child = 17;
  197. else if (l = checkUnary(i)) tokens[i].argument_child = 18;
  198. return l;
  199. }
  200. /**
  201. * @returns {Array} Node that is part of arguments list
  202. */
  203. function getArgument() {
  204. var childType = tokens[pos].argument_child;
  205. if (childType === 1) return getBraces();
  206. else if (childType === 2) return getDeclaration();
  207. else if (childType === 3) return getFunction();
  208. else if (childType === 4) return getVariablesList();
  209. else if (childType === 5) return getVariable();
  210. else if (childType === 6) return getSC();
  211. else if (childType === 7) return getDelim();
  212. else if (childType === 8) return getDeclDelim();
  213. else if (childType === 9) return getString();
  214. else if (childType === 10) return getPercentage();
  215. else if (childType === 11) return getDimension();
  216. else if (childType === 12) return getNumber();
  217. else if (childType === 13) return getUri();
  218. else if (childType === 14) return getInterpolation();
  219. else if (childType === 15) return getIdent();
  220. else if (childType === 16) return getVhash();
  221. else if (childType === 17) return getOperator();
  222. else if (childType === 18) return getUnary();
  223. }
  224. /**
  225. * Check if token is part of an @-word (e.g. `@import`, `@include`)
  226. * @param {Number} i Token's index number
  227. * @returns {Number}
  228. */
  229. function checkAtkeyword(i) {
  230. var l;
  231. // Check that token is `@`:
  232. if (i >= tokensLength ||
  233. tokens[i++].type !== TokenType.CommercialAt) return 0;
  234. return (l = checkIdent(i)) ? l + 1 : 0;
  235. }
  236. /**
  237. * Get node with @-word
  238. * @returns {Array} `['atkeyword', ['ident', x]]` where `x` is
  239. * an identifier without
  240. * `@` (e.g. `import`, `include`)
  241. */
  242. function getAtkeyword() {
  243. var startPos = pos++,
  244. x = [getIdent()];
  245. var token = tokens[startPos];
  246. return new Node(NodeType.AtkeywordType, x, token.ln, token.col);
  247. }
  248. /**
  249. * Check if token is part of an attribute selector (e.g. `[attr]`,
  250. * `[attr='panda']`)
  251. * @param {Number} i Token's index number
  252. * @returns {Number}
  253. */
  254. function checkAttrib(i) {
  255. if (i >= tokensLength ||
  256. tokens[i].type !== TokenType.LeftSquareBracket ||
  257. !tokens[i].right) return 0;
  258. return tokens[i].right - i + 1;
  259. }
  260. /**
  261. * Get node with an attribute selector
  262. * @returns {Array} `['attrib', ['ident', x], ['attrselector', y]*, [z]*]`
  263. * where `x` is attribute's name, `y` is operator (if there is any)
  264. * and `z` is attribute's value (if there is any)
  265. */
  266. function getAttrib() {
  267. if (checkAttrib1(pos)) return getAttrib1();
  268. if (checkAttrib2(pos)) return getAttrib2();
  269. }
  270. /**
  271. * Check if token is part of an attribute selector of the form `[attr='value']`
  272. * @param {Number} i Token's index number
  273. * @returns {Number}
  274. */
  275. function checkAttrib1(i) {
  276. var start = i,
  277. l;
  278. if (i++ >= tokensLength) return 0;
  279. if (l = checkSC(i)) i += l;
  280. if (l = checkIdent(i)) i += l;
  281. else return 0;
  282. if (l = checkSC(i)) i += l;
  283. if (l = checkAttrselector(i)) i += l;
  284. else return 0;
  285. if (l = checkSC(i)) i += l;
  286. if (l = checkIdent(i) || checkString(i)) i += l;
  287. else return 0;
  288. if (l = checkSC(i)) i += l;
  289. return tokens[i].type === TokenType.RightSquareBracket ? i - start : 0;
  290. }
  291. /**
  292. * Get node with an attribute selector of the form `[attr='value']`
  293. * @returns {Array} `['attrib', ['ident', x], ['attrselector', y], [z]]`
  294. * where `x` is attribute's name, `y` is operator and `z` is attribute's
  295. * value
  296. */
  297. function getAttrib1() {
  298. var startPos = pos,
  299. x;
  300. pos++;
  301. x = []
  302. .concat(getSC())
  303. .concat([getIdent()])
  304. .concat(getSC())
  305. .concat([getAttrselector()])
  306. .concat(getSC())
  307. .concat([checkString(pos)? getString() : getIdent()])
  308. .concat(getSC());
  309. pos++;
  310. var token = tokens[startPos];
  311. return new Node(NodeType.AttribType, x, token.ln, token.col);
  312. }
  313. /**
  314. * Check if token is part of an attribute selector of the form `[attr]`
  315. * Attribute can not be empty, e.g. `[]`.
  316. * @param {Number} i Token's index number
  317. * @returns {Number}
  318. */
  319. function checkAttrib2(i) {
  320. var start = i,
  321. l;
  322. if (i++ >= tokensLength) return 0;
  323. if (l = checkSC(i)) i += l;
  324. if (l = checkIdent(i)) i += l;
  325. else return 0;
  326. if (l = checkSC(i)) i += l;
  327. return tokens[i].type === TokenType.RightSquareBracket ? i - start : 0;
  328. }
  329. /**
  330. * Get node with an attribute selector of the form `[attr]`
  331. * @returns {Array} `['attrib', ['ident', x]]` where `x` is attribute's name
  332. */
  333. function getAttrib2() {
  334. var startPos = pos,
  335. x;
  336. pos++;
  337. x = []
  338. .concat(getSC())
  339. .concat([getIdent()])
  340. .concat(getSC());
  341. pos++;
  342. var token = tokens[startPos];
  343. return new Node(NodeType.AttribType, x, token.ln, token.col);
  344. }
  345. /**
  346. * Check if token is part of an attribute selector operator (`=`, `~=`,
  347. * `^=`, `$=`, `*=` or `|=`)
  348. * @param {Number} i Token's index number
  349. * @returns {Number} Length of operator (`0` if token is not part of an
  350. * operator, `1` or `2` if it is).
  351. */
  352. function checkAttrselector(i) {
  353. if (i >= tokensLength) return 0;
  354. if (tokens[i].type === TokenType.EqualsSign) return 1;
  355. // TODO: Add example or remove
  356. if (tokens[i].type === TokenType.VerticalLine &&
  357. (!tokens[i + 1] || tokens[i + 1].type !== TokenType.EqualsSign))
  358. return 1;
  359. if (!tokens[i + 1] || tokens[i + 1].type !== TokenType.EqualsSign) return 0;
  360. switch(tokens[i].type) {
  361. case TokenType.Tilde:
  362. case TokenType.CircumflexAccent:
  363. case TokenType.DollarSign:
  364. case TokenType.Asterisk:
  365. case TokenType.VerticalLine:
  366. return 2;
  367. }
  368. return 0;
  369. }
  370. /**
  371. * Get node with an attribute selector operator (`=`, `~=`, `^=`, `$=`,
  372. * `*=` or `|=`)
  373. * @returns {Array} `['attrselector', x]` where `x` is an operator.
  374. */
  375. function getAttrselector() {
  376. var startPos = pos,
  377. s = tokens[pos++].value;
  378. if (tokens[pos] && tokens[pos].type === TokenType.EqualsSign)
  379. s += tokens[pos++].value;
  380. var token = tokens[startPos];
  381. return new Node(NodeType.AttrselectorType, s, token.ln, token.col);
  382. }
  383. /**
  384. * Check if token is a part of an @-rule
  385. * @param {Number} i Token's index number
  386. * @returns {Number} Length of @-rule
  387. */
  388. function checkAtrule(i) {
  389. var l;
  390. if (i >= tokensLength) return 0;
  391. // If token already has a record of being part of an @-rule,
  392. // return the @-rule's length:
  393. if (tokens[i].atrule_l !== undefined) return tokens[i].atrule_l;
  394. // If token is part of an @-rule, save the rule's type to token:
  395. if (l = checkAtruler(i)) tokens[i].atrule_type = 1; // @-rule with ruleset
  396. else if (l = checkAtruleb(i)) tokens[i].atrule_type = 2; // block @-rule
  397. else if (l = checkAtrules(i)) tokens[i].atrule_type = 3; // single-line @-rule
  398. else return 0;
  399. // If token is part of an @-rule, save the rule's length to token:
  400. tokens[i].atrule_l = l;
  401. return l;
  402. }
  403. /**
  404. * Get node with @-rule
  405. * @returns {Array}
  406. */
  407. function getAtrule() {
  408. switch (tokens[pos].atrule_type) {
  409. case 1: return getAtruler(); // @-rule with ruleset
  410. case 2: return getAtruleb(); // block @-rule
  411. case 3: return getAtrules(); // single-line @-rule
  412. }
  413. }
  414. /**
  415. * Check if token is part of a block @-rule
  416. * @param {Number} i Token's index number
  417. * @returns {Number} Length of the @-rule
  418. */
  419. function checkAtruleb(i) {
  420. var start = i,
  421. l;
  422. if (i >= tokensLength) return 0;
  423. if (l = checkAtkeyword(i)) i += l;
  424. else return 0;
  425. if (l = checkTsets(i)) i += l;
  426. if (l = checkBlock(i)) i += l;
  427. else return 0;
  428. return i - start;
  429. }
  430. /**
  431. * Get node with a block @-rule
  432. * @returns {Array} `['atruleb', ['atkeyword', x], y, ['block', z]]`
  433. */
  434. function getAtruleb() {
  435. var startPos = pos,
  436. x;
  437. x = [getAtkeyword()]
  438. .concat(getTsets())
  439. .concat([getBlock()]);
  440. var token = tokens[startPos];
  441. return new Node(NodeType.AtrulebType, x, token.ln, token.col);
  442. }
  443. /**
  444. * Check if token is part of an @-rule with ruleset
  445. * @param {Number} i Token's index number
  446. * @returns {Number} Length of the @-rule
  447. */
  448. function checkAtruler(i) {
  449. var start = i,
  450. l;
  451. if (i >= tokensLength) return 0;
  452. if (l = checkAtkeyword(i)) i += l;
  453. else return 0;
  454. if (l = checkAtrulerq(i)) i += l;
  455. if (i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket) i++;
  456. else return 0;
  457. if (l = checkAtrulers(i)) i += l;
  458. if (i < tokensLength && tokens[i].type === TokenType.RightCurlyBracket) i++;
  459. else return 0;
  460. return i - start;
  461. }
  462. /**
  463. * Get node with an @-rule with ruleset
  464. * @returns {Array} ['atruler', ['atkeyword', x], y, z]
  465. */
  466. function getAtruler() {
  467. var startPos = pos,
  468. x;
  469. x = [getAtkeyword(), getAtrulerq()];
  470. pos++;
  471. x.push(getAtrulers());
  472. pos++;
  473. var token = tokens[startPos];
  474. return new Node(NodeType.AtrulerType, x, token.ln, token.col);
  475. }
  476. /**
  477. * @param {Number} i Token's index number
  478. * @returns {Number}
  479. */
  480. function checkAtrulerq(i) {
  481. return checkTsets(i);
  482. }
  483. /**
  484. * @returns {Array} `['atrulerq', x]`
  485. */
  486. function getAtrulerq() {
  487. var startPos = pos,
  488. x = getTsets();
  489. var token = tokens[startPos];
  490. return new Node(NodeType.AtrulerqType, x, token.ln, token.col);
  491. }
  492. /**
  493. * @param {Number} i Token's index number
  494. * @returns {Number}
  495. */
  496. function checkAtrulers(i) {
  497. var start = i,
  498. l;
  499. if (i >= tokensLength) return 0;
  500. if (l = checkSC(i)) i += l;
  501. while (l = checkRuleset(i) || checkAtrule(i) || checkSC(i)) {
  502. i += l;
  503. }
  504. tokens[i].atrulers_end = 1;
  505. if (l = checkSC(i)) i += l;
  506. return i - start;
  507. }
  508. /**
  509. * @returns {Array} `['atrulers', x]`
  510. */
  511. function getAtrulers() {
  512. var startPos = pos,
  513. x = getSC();
  514. while (!tokens[pos].atrulers_end) {
  515. if (checkSC(pos)) x = x.concat(getSC());
  516. else if (checkAtrule(pos)) x.push(getAtrule());
  517. else if (checkRuleset(pos)) x.push(getRuleset());
  518. }
  519. x = x.concat(getSC());
  520. var token = tokens[startPos];
  521. return new Node(NodeType.AtrulersType, x, token.ln, token.col);
  522. }
  523. /**
  524. * @param {Number} i Token's index number
  525. * @returns {Number}
  526. */
  527. function checkAtrules(i) {
  528. var start = i,
  529. l;
  530. if (i >= tokensLength) return 0;
  531. if (l = checkAtkeyword(i)) i += l;
  532. else return 0;
  533. if (l = checkTsets(i)) i += l;
  534. return i - start;
  535. }
  536. /**
  537. * @returns {Array} `['atrules', ['atkeyword', x], y]`
  538. */
  539. function getAtrules() {
  540. var startPos = pos,
  541. x;
  542. x = [getAtkeyword()].concat(getTsets());
  543. var token = tokens[startPos];
  544. return new Node(NodeType.AtrulesType, x, token.ln, token.col);
  545. }
  546. /**
  547. * Check if token is part of a block (e.g. `{...}`).
  548. * @param {Number} i Token's index number
  549. * @returns {Number} Length of the block
  550. */
  551. function checkBlock(i) {
  552. return i < tokensLength && tokens[i].block_end ?
  553. tokens[i].block_end - i + 1 : 0;
  554. }
  555. /**
  556. * Get node with a block
  557. * @returns {Array} `['block', x]`
  558. */
  559. function getBlock() {
  560. var startPos = pos,
  561. end = tokens[pos].block_end,
  562. x = [];
  563. while (pos < end) {
  564. if (checkBlockdecl(pos)) x = x.concat(getBlockdecl());
  565. else throwError();
  566. }
  567. var token = tokens[startPos];
  568. return new Node(NodeType.BlockType, x, token.ln, token.col);
  569. }
  570. /**
  571. * Check if token is part of a declaration (property-value pair)
  572. * @param {Number} i Token's index number
  573. * @returns {Number} Length of the declaration
  574. */
  575. function checkBlockdecl(i) {
  576. var l;
  577. if (i >= tokensLength) return 0;
  578. if (l = checkBlockdecl1(i)) tokens[i].bd_type = 1;
  579. else if (l = checkBlockdecl2(i)) tokens[i].bd_type = 2;
  580. else if (l = checkBlockdecl3(i)) tokens[i].bd_type = 3;
  581. else if (l = checkBlockdecl4(i)) tokens[i].bd_type = 4;
  582. else return 0;
  583. return l;
  584. }
  585. /**
  586. * @returns {Array}
  587. */
  588. function getBlockdecl() {
  589. switch (tokens[pos].bd_type) {
  590. case 1: return getBlockdecl1();
  591. case 2: return getBlockdecl2();
  592. case 3: return getBlockdecl3();
  593. case 4: return getBlockdecl4();
  594. }
  595. }
  596. /**
  597. * @param {Number} i Token's index number
  598. * @returns {Number}
  599. */
  600. function checkBlockdecl1(i) {
  601. var start = i,
  602. l;
  603. if (l = checkSC(i)) i += l;
  604. if (l = checkConditionalStatement(i)) tokens[i].bd_kind = 1;
  605. else if (l = checkInclude(i)) tokens[i].bd_kind = 2;
  606. else if (l = checkLoop(i)) tokens[i].bd_kind = 3;
  607. else if (l = checkFilter(i)) tokens[i].bd_kind = 4;
  608. else if (l = checkDeclaration(i)) tokens[i].bd_kind = 5;
  609. else if (l = checkAtrule(i)) tokens[i].bd_kind = 6;
  610. else if (l = checkRuleset(i)) tokens[i].bd_kind = 7;
  611. else return 0;
  612. i += l;
  613. if (i >= tokensLength) return 0;
  614. while (i < tokensLength) {
  615. if (l = checkDeclDelim(i)) {
  616. i += l;
  617. while (i < tokensLength &&
  618. (l = checkS(i)) &&
  619. tokens[i].type === 'Newline') i += l;
  620. break;
  621. } else if (l = checkS(i)) i += l;
  622. else if (l = checkCommentSL(i)) i += l;
  623. else return 0;
  624. }
  625. return i - start;
  626. }
  627. /**
  628. * @returns {Array}
  629. */
  630. function getBlockdecl1() {
  631. var sc = getSC(),
  632. x;
  633. switch (tokens[pos].bd_kind) {
  634. case 1:
  635. x = getConditionalStatement();
  636. break;
  637. case 2:
  638. x = getInclude();
  639. break;
  640. case 3:
  641. x = getLoop();
  642. break;
  643. case 4:
  644. x = getFilter();
  645. break;
  646. case 5:
  647. x = getDeclaration();
  648. break;
  649. case 6:
  650. x = getAtrule();
  651. break;
  652. case 7:
  653. x = getRuleset();
  654. break;
  655. }
  656. x = sc.concat([x]);
  657. while (pos < tokensLength) {
  658. if (checkDeclDelim(pos)) {
  659. x.push(getDeclDelim());
  660. while (pos < tokensLength &&
  661. checkS(pos) &&
  662. tokens[pos].type === 'Newline') x.push(getS());
  663. break;
  664. } else if (checkS(pos)) x.push(getS());
  665. else if (checkCommentSL(pos)) x.push(getCommentSL());
  666. else break;
  667. }
  668. return x;
  669. }
  670. /**
  671. * @param {Number} i Token's index number
  672. * @returns {Number}
  673. */
  674. function checkBlockdecl2(i) {
  675. var start = i,
  676. l;
  677. if (l = checkSC(i)) i += l;
  678. if (l = checkConditionalStatement(i)) tokens[i].bd_kind = 1;
  679. else if (l = checkInclude(i)) tokens[i].bd_kind = 2;
  680. else if (l = checkLoop(i)) tokens[i].bd_kind = 3;
  681. else if (l = checkFilter(i)) tokens[i].bd_kind = 4;
  682. else if (l = checkDeclaration(i)) tokens[i].bd_kind = 5;
  683. else if (l = checkAtrule(i)) tokens[i].bd_kind = 6;
  684. else if (l = checkRuleset(i)) tokens[i].bd_kind = 7;
  685. else return 0;
  686. i += l;
  687. return i - start;
  688. }
  689. /**
  690. * @returns {Array}
  691. */
  692. function getBlockdecl2() {
  693. var sc = getSC(),
  694. x;
  695. switch (tokens[pos].bd_kind) {
  696. case 1:
  697. x = getConditionalStatement();
  698. break;
  699. case 2:
  700. x = getInclude();
  701. break;
  702. case 3:
  703. x = getLoop();
  704. break;
  705. case 4:
  706. x = getFilter();
  707. break;
  708. case 5:
  709. x = getDeclaration();
  710. break;
  711. case 6:
  712. x = getAtrule();
  713. break;
  714. case 7:
  715. x = getRuleset();
  716. break;
  717. }
  718. return sc.concat([x]);
  719. }
  720. /**
  721. * @param {Number} i Token's index number
  722. * @returns {Number}
  723. */
  724. function checkBlockdecl3(i) {
  725. var start = i,
  726. l;
  727. if (l = checkSC(i)) i += l;
  728. if (l = checkDeclDelim(i)) i += l;
  729. else return 0;
  730. if (l = checkSC(i)) i += l;
  731. return i - start;
  732. }
  733. /**
  734. * @returns {Array} `[s0, ['declDelim'], s1]` where `s0` and `s1` are
  735. * are optional whitespaces.
  736. */
  737. function getBlockdecl3() {
  738. return getSC()
  739. .concat([getDeclDelim()])
  740. .concat(getSC());
  741. }
  742. /**
  743. * @param {Number} i Token's index number
  744. * @returns {Number}
  745. */
  746. function checkBlockdecl4(i) {
  747. return checkSC(i);
  748. }
  749. /**
  750. * @returns {Array}
  751. */
  752. function getBlockdecl4() {
  753. return getSC();
  754. }
  755. /**
  756. * Check if token is part of text inside parentheses or square brackets
  757. * (e.g. `(1)`)
  758. * @param {Number} i Token's index number
  759. * @returns {Number}
  760. */
  761. function checkBraces(i) {
  762. if (i >= tokensLength ||
  763. (tokens[i].type !== TokenType.LeftParenthesis &&
  764. tokens[i].type !== TokenType.LeftSquareBracket)) return 0;
  765. return tokens[i].right - i + 1;
  766. }
  767. /**
  768. * Get node with text inside parentheses or square brackets (e.g. `(1)`)
  769. * @returns {Array} `['braces', l, r, x*]` where `l` is a left bracket
  770. * (e.g. `'('`), `r` is a right bracket (e.g. `')'`) and `x` is
  771. * parsed text inside those brackets (if there is any)
  772. * (e.g. `['number', '1']`)
  773. */
  774. function getBraces() {
  775. var startPos = pos,
  776. left = pos,
  777. right = tokens[pos].right,
  778. x;
  779. pos++;
  780. var tsets = getTsets();
  781. pos++;
  782. x = [tokens[left].value, tokens[right].value]
  783. .concat(tsets);
  784. var token = tokens[startPos];
  785. return new Node(NodeType.BracesType, x, token.ln, token.col);
  786. }
  787. /**
  788. * Check if token is part of a class selector (e.g. `.abc`)
  789. * @param {Number} i Token's index number
  790. * @returns {Number} Length of the class selector
  791. */
  792. function checkClass(i) {
  793. var start = i,
  794. l;
  795. if (i >= tokensLength) return 0;
  796. if (tokens[i].class_l) return tokens[i].class_l;
  797. if (tokens[i++].type !== TokenType.FullStop) return 0;
  798. while (i < tokensLength) {
  799. if (l = checkInterpolation(i) || checkIdent(i)) i += l;
  800. else break;
  801. }
  802. return i - start;
  803. }
  804. /**
  805. * Get node with a class selector
  806. * @returns {Array} `['class', ['ident', x]]` where x is a class's
  807. * identifier (without `.`, e.g. `abc`).
  808. */
  809. function getClass() {
  810. var startPos = pos++,
  811. x = [];
  812. while (pos < tokensLength) {
  813. if (checkInterpolation(pos)) x.push(getInterpolation());
  814. else if (checkIdent(pos)) x.push(getIdent());
  815. else break;
  816. }
  817. var token = tokens[startPos];
  818. return new Node(NodeType.ClassType, x, token.ln, token.col);
  819. }
  820. /**
  821. * Check if token is a combinator (`+`, `>` or `~`)
  822. * @param {Number} i Token's index number
  823. * @returns {Number} Length of the combinator
  824. */
  825. function checkCombinator(i) {
  826. if (i >= tokensLength) return 0;
  827. switch (tokens[i].type) {
  828. case TokenType.PlusSign:
  829. case TokenType.GreaterThanSign:
  830. case TokenType.Tilde:
  831. return 1;
  832. }
  833. return 0;
  834. }
  835. /**
  836. * Get node with a combinator (`+`, `>` or `~`)
  837. * @returns {Array} `['combinator', x]` where `x` is a combinator
  838. * converted to string.
  839. */
  840. function getCombinator() {
  841. var startPos = pos,
  842. x = tokens[pos++].value;
  843. var token = tokens[startPos];
  844. return new Node(NodeType.CombinatorType, x, token.ln, token.col);
  845. }
  846. /**
  847. * Check if token is a multiline comment.
  848. * @param {Number} i Token's index number
  849. * @returns {Number} `1` if token is a multiline comment, otherwise `0`
  850. */
  851. function checkCommentML(i) {
  852. return i < tokensLength && tokens[i].type === TokenType.CommentML ? 1 : 0;
  853. }
  854. /**
  855. * Get node with a multiline comment
  856. * @returns {Array} `['commentML', x]` where `x`
  857. * is the comment's text (without `/*` and `* /`).
  858. */
  859. function getCommentML() {
  860. var startPos = pos,
  861. x = tokens[pos].value.substring(2);
  862. pos++;
  863. var token = tokens[startPos];
  864. return new Node(NodeType.CommentMLType, x, token.ln, token.col);
  865. }
  866. /**
  867. * Check if token is part of a single-line comment.
  868. * @param {Number} i Token's index number
  869. * @returns {Number} `1` if token is a single-line comment, otherwise `0`
  870. */
  871. function checkCommentSL(i) {
  872. return i < tokensLength && tokens[i].type === TokenType.CommentSL ? 1 : 0;
  873. }
  874. /**
  875. * Get node with a single-line comment.
  876. * @returns {Array} `['commentSL', x]` where `x` is comment's message
  877. * (without `//`)
  878. */
  879. function getCommentSL() {
  880. var startPos = pos,
  881. x = tokens[pos++].value.substring(2);
  882. var token = tokens[startPos];
  883. return new Node(NodeType.CommentSLType, x, token.ln, token.col);
  884. }
  885. /**
  886. * Check if token is part of a condition
  887. * (e.g. `@if ...`, `@else if ...` or `@else ...`).
  888. * @param {Number} i Token's index number
  889. * @returns {Number} Length of the condition
  890. */
  891. function checkCondition(i) {
  892. var start = i,
  893. l, _i, s;
  894. if (i >= tokensLength) return 0;
  895. if (l = checkAtkeyword(i)) i += l;
  896. else return 0;
  897. if (['if', 'else'].indexOf(tokens[start + 1].value) < 0) return 0;
  898. while (i < tokensLength) {
  899. if (l = checkBlock(i)) break;
  900. s = checkSC(i);
  901. _i = i + s;
  902. if (l = _checkCondition(_i)) i += l + s;
  903. else break;
  904. }
  905. return i - start;
  906. }
  907. function _checkCondition(i) {
  908. return checkVariable(i) ||
  909. checkNumber(i) ||
  910. checkIdent(i) ||
  911. checkOperator(i) ||
  912. checkCombinator(i) ||
  913. checkString(i);
  914. }
  915. /**
  916. * Get node with a condition.
  917. * @returns {Array} `['condition', x]`
  918. */
  919. function getCondition() {
  920. var startPos = pos,
  921. x = [getAtkeyword()];
  922. while (pos < tokensLength) {
  923. if (checkBlock(pos)) break;
  924. s = checkSC(pos);
  925. _pos = pos + s;
  926. if (!_checkCondition(_pos)) break;
  927. if (s) x = x.concat(getSC());
  928. x.push(_getCondition());
  929. }
  930. var token = tokens[startPos];
  931. return new Node(NodeType.ConditionType, x, token.ln, token.col);
  932. }
  933. function _getCondition() {
  934. if (checkVariable(pos)) return getVariable();
  935. if (checkNumber(pos)) return getNumber();
  936. if (checkIdent(pos)) return getIdent();
  937. if (checkOperator(pos)) return getOperator();
  938. if (checkCombinator(pos)) return getCombinator();
  939. if (checkString(pos)) return getString();
  940. }
  941. /**
  942. * Check if token is part of a conditional statement
  943. * (e.g. `@if ... {} @else if ... {} @else ... {}`).
  944. * @param {Number} i Token's index number
  945. * @returns {Number} Length of the condition
  946. */
  947. function checkConditionalStatement(i) {
  948. var start = i,
  949. l;
  950. if (i >= tokensLength) return 0;
  951. if (l = checkCondition(i)) i += l;
  952. else return 0;
  953. if (l = checkSC(i)) i += l;
  954. if (l = checkBlock(i)) i += l;
  955. else return 0;
  956. return i - start;
  957. }
  958. /**
  959. * Get node with a condition.
  960. * @returns {Array} `['condition', x]`
  961. */
  962. function getConditionalStatement() {
  963. var startPos = pos,
  964. x = [];
  965. x.push(getCondition());
  966. x = x.concat(getSC());
  967. x.push(getBlock());
  968. var token = tokens[startPos];
  969. return new Node(NodeType.ConditionalStatementType, x, token.ln, token.col);
  970. }
  971. /**
  972. * Check if token is part of a declaration (property-value pair)
  973. * @param {Number} i Token's index number
  974. * @returns {Number} Length of the declaration
  975. */
  976. function checkDeclaration(i) {
  977. return checkDeclaration1(i) || checkDeclaration2(i);
  978. }
  979. /**
  980. * Get node with a declaration
  981. * @returns {Array} `['declaration', ['property', x], ['propertyDelim'],
  982. * ['value', y]]`
  983. */
  984. function getDeclaration() {
  985. return checkDeclaration1(pos) ? getDeclaration1() : getDeclaration2();
  986. }
  987. /**
  988. * Check if token is part of a declaration (property-value pair)
  989. * @param {Number} i Token's index number
  990. * @returns {Number} Length of the declaration
  991. */
  992. function checkDeclaration1(i) {
  993. var start = i,
  994. l;
  995. if (i >= tokensLength) return 0;
  996. if (l = checkProperty(i)) i += l;
  997. else return 0;
  998. if (l = checkSC(i)) i += l;
  999. if (l = checkPropertyDelim(i)) i++;
  1000. else return 0;
  1001. if (l = checkValue(i)) return i + l - start;
  1002. if (l = checkS(i)) i += l;
  1003. if (l = checkValue(i)) i += l;
  1004. else return 0;
  1005. return i - start;
  1006. }
  1007. /**
  1008. * Get node with a declaration
  1009. * @returns {Array} `['declaration', ['property', x], ['propertyDelim'],
  1010. * ['value', y]]`
  1011. */
  1012. function getDeclaration1() {
  1013. var startPos = pos,
  1014. x = [];
  1015. x.push(getProperty());
  1016. if (checkS(pos)) x.push(getS());
  1017. x.push(getPropertyDelim());
  1018. if (checkS(pos)) x.push(getS());
  1019. x.push(getValue());
  1020. var token = tokens[startPos];
  1021. return new Node(NodeType.DeclarationType, x, token.ln, token.col);
  1022. }
  1023. /**
  1024. * Check if token is part of a declaration (property-value pair)
  1025. * @param {Number} i Token's index number
  1026. * @returns {Number} Length of the declaration
  1027. */
  1028. function checkDeclaration2(i) {
  1029. var start = i,
  1030. l;
  1031. if (i >= tokensLength) return 0;
  1032. if (l = checkPropertyDelim(i)) i++;
  1033. else return 0;
  1034. if (l = checkProperty(i)) i += l;
  1035. else return 0;
  1036. if (l = checkValue(i)) return i + l - start;
  1037. if (l = checkSC(i)) i += l;
  1038. if (l = checkValue(i)) i += l;
  1039. else return 0;
  1040. return i - start;
  1041. }
  1042. /**
  1043. * Get node with a declaration
  1044. * @returns {Array} `['declaration', ['propertyDelim'], ['property', x],
  1045. * ['value', y]]`
  1046. */
  1047. function getDeclaration2() {
  1048. var startPos = pos,
  1049. x = [];
  1050. x.push(getPropertyDelim());
  1051. x.push(getProperty());
  1052. x = x.concat(getSC());
  1053. x.push(getValue());
  1054. var token = tokens[startPos];
  1055. return new Node(NodeType.DeclarationType, x, token.ln, token.col);
  1056. }
  1057. /**
  1058. * Check if token is a semicolon
  1059. * @param {Number} i Token's index number
  1060. * @returns {Number} `1` if token is a semicolon, otherwise `0`
  1061. */
  1062. function checkDeclDelim(i) {
  1063. if (i >= tokensLength) return 0;
  1064. return (tokens[i].type === TokenType.Newline ||
  1065. tokens[i].type === TokenType.Semicolon) ? 1 : 0;
  1066. }
  1067. /**
  1068. * Get node with a semicolon
  1069. * @returns {Array} `['declDelim']`
  1070. */
  1071. function getDeclDelim() {
  1072. var startPos = pos++;
  1073. var token = tokens[startPos];
  1074. return new Node(NodeType.DeclDelimType, '\n', token.ln, token.col);
  1075. }
  1076. function checkDeepSelector(i) {
  1077. if (tokens[i + 2] &&
  1078. tokens[i].value + tokens[i + 1].value + tokens[i + 2].value === '/deep/') {
  1079. return 3;
  1080. }
  1081. }
  1082. function getDeepSelector() {
  1083. var _pos = pos++;
  1084. var ident = getIdent();
  1085. ident.content = '/deep/';
  1086. ident.start.column -= 1;
  1087. pos = _pos + 3;
  1088. return ident;
  1089. }
  1090. /**
  1091. * Check if token if part of `!default` word.
  1092. * @param {Number} i Token's index number
  1093. * @returns {Number} Length of the `!default` word
  1094. */
  1095. function checkDefault(i) {
  1096. var start = i,
  1097. l;
  1098. if (i >= tokensLength ||
  1099. tokens[i++].type !== TokenType.ExclamationMark) return 0;
  1100. if (l = checkSC(i)) i += l;
  1101. return tokens[i].value === 'default' ? i - start + 1 : 0;
  1102. }
  1103. /**
  1104. * Get node with a `!default` word
  1105. * @returns {Array} `['default', sc]` where `sc` is optional whitespace
  1106. */
  1107. function getDefault() {
  1108. var startPos = pos,
  1109. x = [],
  1110. sc;
  1111. // Skip `!`:
  1112. pos++;
  1113. sc = getSC();
  1114. // Skip `default`:
  1115. pos++;
  1116. x = x.concat(sc);
  1117. var token = tokens[startPos];
  1118. return new Node(NodeType.DefaultType, x, token.ln, token.col);
  1119. }
  1120. /**
  1121. * Check if token is a comma
  1122. * @param {Number} i Token's index number
  1123. * @returns {Number} `1` if token is a comma, otherwise `0`
  1124. */
  1125. function checkDelim(i) {
  1126. return i < tokensLength && tokens[i].type === TokenType.Comma ? 1 : 0;
  1127. }
  1128. /**
  1129. * Get node with a comma
  1130. * @returns {Array} `['delim']`
  1131. */
  1132. function getDelim() {
  1133. var startPos = pos++;
  1134. var token = tokens[startPos];
  1135. return new Node(NodeType.DelimType, ',', token.ln, token.col);
  1136. }
  1137. /**
  1138. * Check if token is part of a number with dimension unit (e.g. `10px`)
  1139. * @param {Number} i Token's index number
  1140. * @returns {Number}
  1141. */
  1142. function checkDimension(i) {
  1143. var ln = checkNumber(i),
  1144. li;
  1145. if (i >= tokensLength ||
  1146. !ln ||
  1147. i + ln >= tokensLength) return 0;
  1148. return (li = checkNmName2(i + ln)) ? ln + li : 0;
  1149. }
  1150. /**
  1151. * Get node of a number with dimension unit
  1152. * @returns {Array} `['dimension', ['number', x], ['ident', y]]` where
  1153. * `x` is a number converted to string (e.g. `'10'`) and `y` is
  1154. * a dimension unit (e.g. `'px'`).
  1155. */
  1156. function getDimension() {
  1157. var startPos = pos,
  1158. x = [getNumber()],
  1159. token = tokens[pos],
  1160. ident = new Node(NodeType.IdentType, getNmName2(), token.ln, token.col);
  1161. x.push(ident);
  1162. token = tokens[startPos];
  1163. return new Node(NodeType.DimensionType, x, token.ln, token.col);
  1164. }
  1165. /**
  1166. * @param {Number} i Token's index number
  1167. * @returns {Number}
  1168. */
  1169. function checkFilter(i) {
  1170. var start = i,
  1171. l;
  1172. if (i >= tokensLength) return 0;
  1173. if (l = checkFilterp(i)) i += l;
  1174. else return 0;
  1175. if (tokens[i].type === TokenType.Colon) i++;
  1176. else return 0;
  1177. if (l = checkFilterv(i)) i += l;
  1178. else return 0;
  1179. return i - start;
  1180. }
  1181. /**
  1182. * @returns {Array} `['filter', x, y]`
  1183. */
  1184. function getFilter() {
  1185. var startPos = pos,
  1186. x = [getFilterp()];
  1187. pos++;
  1188. x.push(getFilterv());
  1189. var token = tokens[startPos];
  1190. return new Node(NodeType.FilterType, x, token.ln, token.col);
  1191. }
  1192. /**
  1193. * @param {Number} i Token's index number
  1194. * @returns {Number}
  1195. */
  1196. function checkFilterp(i) {
  1197. var start = i,
  1198. l,
  1199. x;
  1200. if (i >= tokensLength) return 0;
  1201. if (tokens[i].value === 'filter') l = 1;
  1202. else {
  1203. x = joinValues2(i, 2);
  1204. if (x === '-filter' || x === '_filter' || x === '*filter') l = 2;
  1205. else {
  1206. x = joinValues2(i, 4);
  1207. if (x === '-ms-filter') l = 4;
  1208. else return 0;
  1209. }
  1210. }
  1211. tokens[start].filterp_l = l;
  1212. i += l;
  1213. if (checkSC(i)) i += l;
  1214. return i - start;
  1215. }
  1216. /**
  1217. * @returns {Array}
  1218. */
  1219. function getFilterp() {
  1220. var startPos = pos,
  1221. token = tokens[pos],
  1222. ident = new Node(NodeType.IdentType, joinValues2(pos, tokens[pos].filterp_l), token.ln, token.col),
  1223. x;
  1224. pos += tokens[pos].filterp_l;
  1225. x = [ident].concat(getSC());
  1226. return new Node(NodeType.PropertyType, x, token.ln, token.col);
  1227. }
  1228. /**
  1229. * @param {Number} i Token's index number
  1230. * @returns {Number}
  1231. */
  1232. function checkFilterv(i) {
  1233. var start = i,
  1234. l;
  1235. if (i >= tokensLength) return 0;
  1236. if (l = checkProgid(i)) i += l;
  1237. else return 0;
  1238. while (l = checkProgid(i)) {
  1239. i += l;
  1240. }
  1241. tokens[start].last_progid = i;
  1242. if (checkDeclDelim(i)) return i - start;
  1243. if (i < tokensLength && (l = checkSC(i))) i += l;
  1244. if (i < tokensLength && (l = checkImportant(i))) i += l;
  1245. return i - start;
  1246. }
  1247. /**
  1248. * progid+:x -> [#filterv].concat(x)
  1249. * @returns {Array}
  1250. */
  1251. function getFilterv() {
  1252. var startPos = pos,
  1253. token = tokens[startPos],
  1254. x = [],
  1255. last_progid = tokens[pos].last_progid;
  1256. while (pos < last_progid) {
  1257. x.push(getProgid());
  1258. }
  1259. if (checkDeclDelim(pos))
  1260. return new Node(NodeType.FiltervType, x, token.ln, token.col);
  1261. if (checkSC(pos)) x = x.concat(getSC());
  1262. if (pos < tokensLength && checkImportant(pos)) x.push(getImportant());
  1263. return new Node(NodeType.FiltervType, x, token.ln, token.col);
  1264. }
  1265. /**
  1266. * @param {Number} i Token's index number
  1267. * @returns {Number}
  1268. */
  1269. function checkFunctionExpression(i) {
  1270. var start = i;
  1271. if (i >= tokensLength || tokens[i++].value !== 'expression' ||
  1272. i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0;
  1273. return tokens[i].right - start + 1;
  1274. }
  1275. /**
  1276. * @returns {Array}
  1277. */
  1278. function getFunctionExpression() {
  1279. var startPos = pos,
  1280. x;
  1281. pos++;
  1282. x = joinValues(pos + 1, tokens[pos].right - 1);
  1283. pos = tokens[pos].right + 1;
  1284. var token = tokens[startPos];
  1285. return new Node(NodeType.FunctionExpressionType, [x], token.ln, token.col);
  1286. }
  1287. /**
  1288. * @param {Number} i Token's index number
  1289. * @returns {Number}
  1290. */
  1291. function checkFunction(i) {
  1292. var start = i,
  1293. l;
  1294. if (i >= tokensLength) return 0;
  1295. if (l = checkIdent(i)) i +=l;
  1296. else return 0;
  1297. return i < tokensLength && tokens[i].type === TokenType.LeftParenthesis ?
  1298. tokens[i].right - start + 1 : 0;
  1299. }
  1300. /**
  1301. * @returns {Array}
  1302. */
  1303. function getFunction() {
  1304. var startPos = pos,
  1305. ident = getIdent(),
  1306. x = [ident],
  1307. body;
  1308. body = ident.content === 'not' ? getNotArguments() : getArguments();
  1309. x.push(body);
  1310. var token = tokens[startPos];
  1311. return new Node(NodeType.FunctionType, x, token.ln, token.col);
  1312. }
  1313. /**
  1314. * @returns {Array}
  1315. */
  1316. function getArguments() {
  1317. var startPos = pos,
  1318. x = [],
  1319. body;
  1320. pos++;
  1321. while (pos < tokensLength && tokens[pos].type !== TokenType.RightParenthesis) {
  1322. if (checkDeclaration(pos)) x.push(getDeclaration());
  1323. else if (checkArgument(pos)) {
  1324. body = getArgument();
  1325. if (typeof body.content === 'string') x.push(body);
  1326. else x = x.concat(body);
  1327. } else if (checkClass(pos)) x.push(getClass());
  1328. else throwError();
  1329. }
  1330. pos++;
  1331. var token = tokens[startPos];
  1332. return new Node(NodeType.ArgumentsType, x, token.ln, token.col);
  1333. }
  1334. /**
  1335. * @returns {Array}
  1336. */
  1337. function getNotArguments() {
  1338. var startPos = pos,
  1339. x = [];
  1340. pos++;
  1341. while (pos < tokensLength &&
  1342. tokens[pos].type !== TokenType.RightParenthesis) {
  1343. if (checkSimpleSelector(pos)) x.push(getSimpleSelector());
  1344. else throwError();
  1345. }
  1346. pos++;
  1347. var token = tokens[startPos];
  1348. return new Node(NodeType.ArgumentsType, x, token.ln, token.col);
  1349. }
  1350. /**
  1351. * Check if token is part of an identifier
  1352. * @param {Number} i Token's index number
  1353. * @returns {Number} Length of the identifier
  1354. */
  1355. function checkIdent(i) {
  1356. var start = i,
  1357. wasIdent,
  1358. wasInt = false,
  1359. l;
  1360. if (i >= tokensLength) return 0;
  1361. // Check if token is part of an identifier starting with `_`:
  1362. if (tokens[i].type === TokenType.LowLine) return checkIdentLowLine(i);
  1363. if (tokens[i].type === TokenType.HyphenMinus &&
  1364. tokens[i + 1].type === TokenType.DecimalNumber) return 0;
  1365. // If token is a character, `-`, `$` or `*`, skip it & continue:
  1366. if (l = _checkIdent(i)) i += l;
  1367. else return 0;
  1368. // Remember if previous token's type was identifier:
  1369. wasIdent = tokens[i - 1].type === TokenType.Identifier;
  1370. while (i < tokensLength) {
  1371. l = _checkIdent(i);
  1372. if (!l) break;
  1373. wasIdent = true;
  1374. i += l;
  1375. }
  1376. if (!wasIdent && !wasInt && tokens[start].type !== TokenType.Asterisk) return 0;
  1377. tokens[start].ident_last = i - 1;
  1378. return i - start;
  1379. }
  1380. function _checkIdent(i) {
  1381. if (tokens[i].type === TokenType.HyphenMinus ||
  1382. tokens[i].type === TokenType.Identifier ||
  1383. tokens[i].type === TokenType.DollarSign ||
  1384. tokens[i].type === TokenType.LowLine ||
  1385. tokens[i].type === TokenType.DecimalNumber ||
  1386. tokens[i].type === TokenType.Asterisk) return 1;
  1387. return 0;
  1388. }
  1389. /**
  1390. * Check if token is part of an identifier starting with `_`
  1391. * @param {Number} i Token's index number
  1392. * @returns {Number} Length of the identifier
  1393. */
  1394. function checkIdentLowLine(i) {
  1395. var start = i;
  1396. if (i++ >= tokensLength) return 0;
  1397. for (; i < tokensLength; i++) {
  1398. if (tokens[i].type !== TokenType.HyphenMinus &&
  1399. tokens[i].type !== TokenType.DecimalNumber &&
  1400. tokens[i].type !== TokenType.LowLine &&
  1401. tokens[i].type !== TokenType.Identifier) break;
  1402. }
  1403. // Save index number of the last token of the identifier:
  1404. tokens[start].ident_last = i - 1;
  1405. return i - start;
  1406. }
  1407. /**
  1408. * Get node with an identifier
  1409. * @returns {Array} `['ident', x]` where `x` is identifier's name
  1410. */
  1411. function getIdent() {
  1412. var startPos = pos,
  1413. x = joinValues(pos, tokens[pos].ident_last);
  1414. pos = tokens[pos].ident_last + 1;
  1415. var token = tokens[startPos];
  1416. return new Node(NodeType.IdentType, x, token.ln, token.col);
  1417. }
  1418. /**
  1419. * Check if token is part of `!important` word
  1420. * @param {Number} i Token's index number
  1421. * @returns {Number}
  1422. */
  1423. function checkImportant(i) {
  1424. var start = i,
  1425. l;
  1426. if (i >= tokensLength ||
  1427. tokens[i++].type !== TokenType.ExclamationMark) return 0;
  1428. if (l = checkSC(i)) i += l;
  1429. return tokens[i].value === 'important' ? i - start + 1 : 0;
  1430. }
  1431. /**
  1432. * Get node with `!important` word
  1433. * @returns {Array} `['important', sc]` where `sc` is optional whitespace
  1434. */
  1435. function getImportant() {
  1436. var startPos = pos++,
  1437. x = getSC();
  1438. pos++;
  1439. var token = tokens[startPos];
  1440. return new Node(NodeType.ImportantType, x, token.ln, token.col);
  1441. }
  1442. /**
  1443. * Check if token is part of an included mixin (`@include` or `@extend`
  1444. * directive).
  1445. * @param {Number} i Token's index number
  1446. * @returns {Number} Length of the included mixin
  1447. */
  1448. function checkInclude(i) {
  1449. var l;
  1450. if (i >= tokensLength) return 0;
  1451. if (l = checkInclude1(i)) tokens[i].include_type = 1;
  1452. else if (l = checkInclude2(i)) tokens[i].include_type = 2;
  1453. else if (l = checkInclude3(i)) tokens[i].include_type = 3;
  1454. else if (l = checkInclude4(i)) tokens[i].include_type = 4;
  1455. else if (l = checkInclude5(i)) tokens[i].include_type = 5;
  1456. else if (l = checkInclude6(i)) tokens[i].include_type = 6;
  1457. else if (l = checkInclude7(i)) tokens[i].include_type = 7;
  1458. else if (l = checkInclude8(i)) tokens[i].include_type = 8;
  1459. return l;
  1460. }
  1461. /**
  1462. * Get node with included mixin
  1463. * @returns {Array} `['include', x]`
  1464. */
  1465. function getInclude() {
  1466. switch (tokens[pos].include_type) {
  1467. case 1: return getInclude1();
  1468. case 2: return getInclude2();
  1469. case 3: return getInclude3();
  1470. case 4: return getInclude4();
  1471. case 5: return getInclude5();
  1472. case 6: return getInclude6();
  1473. case 7: return getInclude7();
  1474. case 8: return getInclude8();
  1475. }
  1476. }
  1477. /**
  1478. * Check if token is part of an included mixin like `@include nani(foo) {...}`
  1479. * @param {Number} i Token's index number
  1480. * @returns {Number} Length of the include
  1481. */
  1482. function checkInclude1(i) {
  1483. var start = i,
  1484. l;
  1485. if (l = checkAtkeyword(i)) i += l;
  1486. else return 0;
  1487. // TODO: Check if extends don't take any arguments
  1488. if (['include', 'extend'].indexOf(tokens[start + 1].value) < 0) return 0;
  1489. if (l = checkSC(i)) i += l;
  1490. else return 0;
  1491. if (l = checkIncludeSelector(i)) i += l;
  1492. else return 0;
  1493. if (l = checkSC(i)) i += l;
  1494. if (l = checkArguments(i)) i += l;
  1495. else return 0;
  1496. if (l = checkSC(i)) i += l;
  1497. if (l = checkBlock(i)) i += l;
  1498. else return 0;
  1499. return i - start;
  1500. }
  1501. /**
  1502. * Get node with included mixin like `@include nani(foo) {...}`
  1503. * @returns {Array} `['include', ['atkeyword', x], sc, ['selector', y], sc,
  1504. * ['arguments', z], sc, ['block', q], sc` where `x` is `include` or
  1505. * `extend`, `y` is mixin's identifier (selector), `z` are arguments
  1506. * passed to the mixin, `q` is block passed to the mixin and `sc`
  1507. * are optional whitespaces
  1508. */
  1509. function getInclude1() {
  1510. var startPos = pos,
  1511. x = [];
  1512. x.push(getAtkeyword());
  1513. x = x.concat(getSC());
  1514. x.push(getIncludeSelector());
  1515. x = x.concat(getSC());
  1516. x.push(getArguments());
  1517. x = x.concat(getSC());
  1518. x.push(getBlock());
  1519. var token = tokens[startPos];
  1520. return new Node(NodeType.IncludeType, x, token.ln, token.col);
  1521. }
  1522. /**
  1523. * Check if token is part of an included mixin like `@include nani(foo)`
  1524. * @param {Number} i Token's index number
  1525. * @returns {Number} Length of the include
  1526. */
  1527. function checkInclude2(i) {
  1528. var start = i,
  1529. l;
  1530. if (l = checkAtkeyword(i)) i += l;
  1531. else return 0;
  1532. // TODO: Check if extends don't take any arguments
  1533. if (['include', 'extend'].indexOf(tokens[start + 1].value) < 0) return 0;
  1534. if (l = checkSC(i)) i += l;
  1535. else return 0;
  1536. if (l = checkIncludeSelector(i)) i += l;
  1537. else return 0;
  1538. if (l = checkSC(i)) i += l;
  1539. if (l = checkArguments(i)) i += l;
  1540. else return 0;
  1541. return i - start;
  1542. }
  1543. /**
  1544. * Get node with included mixin like `@include nani(foo)`
  1545. * @returns {Array} `['include', ['atkeyword', x], sc, ['selector', y], sc,
  1546. * ['arguments', z], sc]` where `x` is `include` or `extend`, `y` is
  1547. * mixin's identifier (selector), `z` are arguments passed to the
  1548. * mixin and `sc` are optional whitespaces
  1549. */
  1550. function getInclude2() {
  1551. var startPos = pos,
  1552. x = [];
  1553. x.push(getAtkeyword());
  1554. x = x.concat(getSC());
  1555. x.push(getIncludeSelector());
  1556. x = x.concat(getSC());
  1557. x.push(getArguments());
  1558. var token = tokens[startPos];
  1559. return new Node(NodeType.IncludeType, x, token.ln, token.col);
  1560. }
  1561. /**
  1562. * Check if token is part of an included mixin with a content block passed
  1563. * as an argument (e.g. `@include nani {...}`)
  1564. * @param {Number} i Token's index number
  1565. * @returns {Number} Length of the mixin
  1566. */
  1567. function checkInclude3(i) {
  1568. var start = i,
  1569. l;
  1570. if (l = checkAtkeyword(i)) i += l;
  1571. else return 0;
  1572. if (['include', 'extend'].indexOf(tokens[start + 1].value) < 0) return 0;
  1573. if (l = checkSC(i)) i += l;
  1574. else return 0;
  1575. if (l = checkIncludeSelector(i)) i += l;
  1576. else return 0;
  1577. if (l = checkSC(i)) i += l;
  1578. if (l = checkBlock(i)) i += l;
  1579. else return 0;
  1580. return i - start;
  1581. }
  1582. /**
  1583. * Get node with an included mixin with a content block passed
  1584. * as an argument (e.g. `@include nani {...}`)
  1585. * @returns {Array} `['include', x]`
  1586. */
  1587. function getInclude3() {
  1588. var startPos = pos,
  1589. x = [];
  1590. x.push(getAtkeyword());
  1591. x = x.concat(getSC());
  1592. x.push(getIncludeSelector());
  1593. x = x.concat(getSC());
  1594. x.push(getBlock());
  1595. var token = tokens[startPos];
  1596. return new Node(NodeType.IncludeType, x, token.ln, token.col);
  1597. }
  1598. /**
  1599. * @param {Number} i Token's index number
  1600. * @returns {Number}
  1601. */
  1602. function checkInclude4(i) {
  1603. var start = i,
  1604. l;
  1605. if (l = checkAtkeyword(i)) i += l;
  1606. else return 0;
  1607. if (['include', 'extend'].indexOf(tokens[start + 1].value) < 0) return 0;
  1608. if (l = checkSC(i)) i += l;
  1609. else return 0;
  1610. if (l = checkIncludeSelector(i)) i += l;
  1611. else return 0;
  1612. return i - start;
  1613. }
  1614. /**
  1615. * @returns {Array} `['include', x]`
  1616. */
  1617. function getInclude4() {
  1618. var startPos = pos,
  1619. x = [];
  1620. x.push(getAtkeyword());
  1621. x = x.concat(getSC());
  1622. x.push(getIncludeSelector());
  1623. var token = tokens[startPos];
  1624. return new Node(NodeType.IncludeType, x, token.ln, token.col);
  1625. }
  1626. /**
  1627. * Check if token is part of an included mixin like `+nani(foo) {...}`
  1628. * @param {Number} i Token's index number
  1629. * @returns {Number} Length of the include
  1630. */
  1631. function checkInclude5(i) {
  1632. var start = i,
  1633. l;
  1634. if (tokens[i].type === TokenType.PlusSign) i++;
  1635. else return 0;
  1636. if (l = checkIncludeSelector(i)) i += l;
  1637. else return 0;
  1638. if (l = checkSC(i)) i += l;
  1639. if (l = checkArguments(i)) i += l;
  1640. else return 0;
  1641. if (l = checkSC(i)) i += l;
  1642. if (l = checkBlock(i)) i += l;
  1643. else return 0;
  1644. if (l = checkSC(i)) i += l;
  1645. return i - start;
  1646. }
  1647. /**
  1648. * Get node with included mixin like `+nani(foo) {...}`
  1649. * @returns {Array} `['include', ['operator', '+'], ['selector', x], sc,
  1650. * ['arguments', y], sc, ['block', z], sc` where `x` is
  1651. * mixin's identifier (selector), `y` are arguments passed to the
  1652. * mixin, `z` is block passed to mixin and `sc` are optional whitespaces
  1653. */
  1654. function getInclude5() {
  1655. var startPos = pos,
  1656. x = [];
  1657. x.push(getOperator());
  1658. x.push(getIncludeSelector());
  1659. x = x.concat(getSC());
  1660. x.push(getArguments());
  1661. x = x.concat(getSC());
  1662. x.push(getBlock());
  1663. x = x.concat(getSC());
  1664. var token = tokens[startPos];
  1665. return new Node(NodeType.IncludeType, x, token.ln, token.col);
  1666. }
  1667. /**
  1668. * Check if token is part of an included mixin like `+nani(foo)`
  1669. * @param {Number} i Token's index number
  1670. * @returns {Number} Length of the include
  1671. */
  1672. function checkInclude6(i) {
  1673. var start = i,
  1674. l;
  1675. if (tokens[i].type === TokenType.PlusSign) i++;
  1676. else return 0;
  1677. if (l = checkIncludeSelector(i)) i += l;
  1678. else return 0;
  1679. if (l = checkSC(i)) i += l;
  1680. if (l = checkArguments(i)) i += l;
  1681. else return 0;
  1682. if (l = checkSC(i)) i += l;
  1683. return i - start;
  1684. }
  1685. /**
  1686. * Get node with included mixin like `+nani(foo)`
  1687. * @returns {Array} `['include', ['operator', '+'], ['selector', y], sc,
  1688. * ['arguments', z], sc]` where `y` is
  1689. * mixin's identifier (selector), `z` are arguments passed to the
  1690. * mixin and `sc` are optional whitespaces
  1691. */
  1692. function getInclude6() {
  1693. var startPos = pos,
  1694. x = [];
  1695. x.push(getOperator());
  1696. x.push(getIncludeSelector());
  1697. x = x.concat(getSC());
  1698. x.push(getArguments());
  1699. x = x.concat(getSC());
  1700. var token = tokens[startPos];
  1701. return new Node(NodeType.IncludeType, x, token.ln, token.col);
  1702. }
  1703. /**
  1704. * Check if token is part of an included mixin with a content block passed
  1705. * as an argument (e.g. `+nani {...}`)
  1706. * @param {Number} i Token's index number
  1707. * @returns {Number} Length of the mixin
  1708. */
  1709. function checkInclude7(i) {
  1710. var start = i,
  1711. l;
  1712. if (tokens[i].type === TokenType.PlusSign) i++;
  1713. else return 0;
  1714. if (l = checkIncludeSelector(i)) i += l;
  1715. else return 0;
  1716. if (l = checkSC(i)) i += l;
  1717. if (l = checkBlock(i)) i += l;
  1718. else return 0;
  1719. if (l = checkSC(i)) i += l;
  1720. return i - start;
  1721. }
  1722. /**
  1723. * Get node with an included mixin with a content block passed
  1724. * as an argument (e.g. `+nani {...}`)
  1725. * @returns {Array} `['include', x]`
  1726. */
  1727. function getInclude7() {
  1728. var startPos = pos,
  1729. x = [];
  1730. x.push(getOperator());
  1731. x.push(getIncludeSelector());
  1732. x = x.concat(getSC());
  1733. x.push(getBlock());
  1734. x = x.concat(getSC());
  1735. var token = tokens[startPos];
  1736. return new Node(NodeType.IncludeType, x, token.ln, token.col);
  1737. }
  1738. /**
  1739. * @param {Number} i Token's index number
  1740. * @returns {Number}
  1741. */
  1742. function checkInclude8(i) {
  1743. var start = i,
  1744. l;
  1745. if (tokens[i].type === TokenType.PlusSign) i++;
  1746. else return 0;
  1747. if (l = checkIncludeSelector(i)) i += l;
  1748. else return 0;
  1749. return i - start;
  1750. }
  1751. /**
  1752. * @returns {Array} `['include', x]`
  1753. */
  1754. function getInclude8() {
  1755. var startPos = pos,
  1756. x = [];
  1757. x.push(getOperator());
  1758. x.push(getIncludeSelector());
  1759. var token = tokens[startPos];
  1760. return new Node(NodeType.IncludeType, x, token.ln, token.col);
  1761. }
  1762. /**
  1763. * @param {Number} i Token's index number
  1764. * @returns {Number}
  1765. */
  1766. function checkIncludeSelector(i) {
  1767. var start = i,
  1768. l;
  1769. while (i < tokensLength) {
  1770. if (l = checkSimpleSelector2(i)) i += l;
  1771. else break;
  1772. }
  1773. return i - start;
  1774. }
  1775. /**
  1776. * @returns {Array}
  1777. */
  1778. function getIncludeSelector() {
  1779. var startPos = pos,
  1780. x = [],
  1781. t;
  1782. while (pos < tokensLength && checkSimpleSelector2(pos)) {
  1783. t = getSimpleSelector2();
  1784. if (typeof t.content === 'string') x.push(t);
  1785. else x = x.concat(t);
  1786. }
  1787. var token = tokens[startPos];
  1788. return new Node(NodeType.SimpleselectorType, x, token.ln, token.col);
  1789. }
  1790. /**
  1791. * Check if token is part of an interpolated variable (e.g. `#{$nani}`).
  1792. * @param {Number} i Token's index number
  1793. * @returns {Number}
  1794. */
  1795. function checkInterpolation(i) {
  1796. var start = i,
  1797. l;
  1798. if (i >= tokensLength) return 0;
  1799. if (tokens[i].type !== TokenType.NumberSign ||
  1800. !tokens[i + 1] ||
  1801. tokens[i + 1].type !== TokenType.LeftCurlyBracket) return 0;
  1802. i += 2;
  1803. if (l = checkVariable(i)) i += l;
  1804. else return 0;
  1805. return tokens[i].type === TokenType.RightCurlyBracket ? i - start + 1 : 0;
  1806. }
  1807. /**
  1808. * Get node with an interpolated variable
  1809. * @returns {Array} `['interpolation', x]`
  1810. */
  1811. function getInterpolation() {
  1812. var startPos = pos,
  1813. x = [];
  1814. // Skip `#{`:
  1815. pos += 2;
  1816. x.push(getVariable());
  1817. // Skip `}`:
  1818. pos++;
  1819. var token = tokens[startPos];
  1820. return new Node(NodeType.InterpolationType, x, token.ln, token.col);
  1821. }
  1822. /**
  1823. * Check if token is part of a loop.
  1824. * @param {Number} i Token's index number
  1825. * @returns {Number} Length of the loop
  1826. */
  1827. function checkLoop(i) {
  1828. var start = i,
  1829. l;
  1830. if (i >= tokensLength) return 0;
  1831. if (l = checkAtkeyword(i)) i += l;
  1832. else return 0;
  1833. if (['for', 'each', 'while'].indexOf(tokens[start + 1].value) < 0) return 0;
  1834. while (i < tokensLength) {
  1835. if (l = checkBlock(i)) {
  1836. i += l;
  1837. break;
  1838. } else if (l = checkVariable(i) ||
  1839. checkNumber(i) ||
  1840. checkIdent(i) ||
  1841. checkSC(i) ||
  1842. checkOperator(i) ||
  1843. checkCombinator(i) ||
  1844. checkString(i)) i += l;
  1845. else return 0;
  1846. }
  1847. return i - start;
  1848. }
  1849. /**
  1850. * Get node with a loop.
  1851. * @returns {Array} `['loop', x]`
  1852. */
  1853. function getLoop() {
  1854. var startPos = pos,
  1855. x = [];
  1856. x.push(getAtkeyword());
  1857. while (pos < tokensLength) {
  1858. if (checkBlock(pos)) {
  1859. x.push(getBlock());
  1860. break;
  1861. }
  1862. else if (checkVariable(pos)) x.push(getVariable());
  1863. else if (checkNumber(pos)) x.push(getNumber());
  1864. else if (checkIdent(pos)) x.push(getIdent());
  1865. else if (checkOperator(pos)) x.push(getOperator());
  1866. else if (checkCombinator(pos)) x.push(getCombinator());
  1867. else if (checkSC(pos)) x = x.concat(getSC());
  1868. else if (checkString(pos)) x.push(getString());
  1869. }
  1870. var token = tokens[startPos];
  1871. return new Node(NodeType.LoopType, x, token.ln, token.col);
  1872. }
  1873. /**
  1874. * Check if token is part of a mixin
  1875. * @param {Number} i Token's index number
  1876. * @returns {Number} Length of the mixin
  1877. */
  1878. function checkMixin(i) {
  1879. return checkMixin1(i) || checkMixin2(i);
  1880. }
  1881. /**
  1882. * Get node with a mixin
  1883. * @returns {Array} `['mixin', x]`
  1884. */
  1885. function getMixin() {
  1886. return checkMixin1(pos) ? getMixin1() : getMixin2();
  1887. }
  1888. /**
  1889. * Check if token is part of a mixin
  1890. * @param {Number} i Token's index number
  1891. * @returns {Number} Length of the mixin
  1892. */
  1893. function checkMixin1(i) {
  1894. var start = i,
  1895. l;
  1896. if (i >= tokensLength) return 0;
  1897. if ((l = checkAtkeyword(i)) && tokens[i + 1].value === 'mixin') i += l;
  1898. else return 0;
  1899. if (l = checkSC(i)) i += l;
  1900. if (l = checkIdent(i)) i += l;
  1901. else return 0;
  1902. if (l = checkSC(i)) i += l;
  1903. if (l = checkBlock(i)) i += l;
  1904. else {
  1905. if (l = checkArguments(i)) i += l;
  1906. if (l = checkSC(i)) i += l;
  1907. if (l = checkBlock(i)) i += l;
  1908. else return 0;
  1909. }
  1910. return i - start;
  1911. }
  1912. /**
  1913. * Get node with a mixin
  1914. * @returns {Array} `['mixin', x]`
  1915. */
  1916. function getMixin1() {
  1917. var startPos = pos,
  1918. x = [getAtkeyword()];
  1919. x = x.concat(getSC());
  1920. if (checkIdent(pos)) x.push(getIdent());
  1921. x = x.concat(getSC());
  1922. if (checkBlock(pos)) x.push(getBlock());
  1923. else {
  1924. if (checkArguments(pos)) x.push(getArguments());
  1925. x = x.concat(getSC());
  1926. x.push(getBlock());
  1927. }
  1928. var token = tokens[startPos];
  1929. return new Node(NodeType.MixinType, x, token.ln, token.col);
  1930. }
  1931. /**
  1932. * Check if token is part of a mixin
  1933. * @param {Number} i Token's index number
  1934. * @returns {Number} Length of the mixin
  1935. */
  1936. function checkMixin2(i) {
  1937. var start = i,
  1938. l;
  1939. if (i >= tokensLength) return 0;
  1940. if (tokens[i].type === TokenType.EqualsSign) i++;
  1941. else return 0;
  1942. if (l = checkSC(i)) i += l;
  1943. if (l = checkIdent(i)) i += l;
  1944. else return 0;
  1945. if (l = checkSC(i)) i += l;
  1946. if (l = checkBlock(i)) i += l;
  1947. else {
  1948. if (l = checkArguments(i)) i += l;
  1949. if (l = checkSC(i)) i += l;
  1950. if (l = checkBlock(i)) i += l;
  1951. else return 0;
  1952. }
  1953. return i - start;
  1954. }
  1955. /**
  1956. * Get node with a mixin
  1957. * @returns {Array} `['mixin', x]`
  1958. */
  1959. function getMixin2() {
  1960. var startPos = pos,
  1961. x = [getOperator()];
  1962. x = x.concat(getSC());
  1963. if (checkIdent(pos)) x.push(getIdent());
  1964. x = x.concat(getSC());
  1965. if (checkBlock(pos)) x.push(getBlock());
  1966. else {
  1967. if (checkArguments(pos)) x.push(getArguments());
  1968. x = x.concat(getSC());
  1969. x.push(getBlock());
  1970. }
  1971. var token = tokens[startPos];
  1972. return new Node(NodeType.MixinType, x, token.ln, token.col);
  1973. }
  1974. /**
  1975. * Check if token is a namespace sign (`|`)
  1976. * @param {Number} i Token's index number
  1977. * @returns {Number} `1` if token is `|`, `0` if not
  1978. */
  1979. function checkNamespace(i) {
  1980. return i < tokensLength && tokens[i].type === TokenType.VerticalLine ? 1 : 0;
  1981. }
  1982. /**
  1983. * Get node with a namespace sign
  1984. * @returns {Array} `['namespace']`
  1985. */
  1986. function getNamespace() {
  1987. var startPos = pos++;
  1988. var token = tokens[startPos];
  1989. return new Node(NodeType.NamespaceType, '|', token.ln, token.col);
  1990. }
  1991. /**
  1992. * @param {Number} i Token's index number
  1993. * @returns {Number}
  1994. */
  1995. function checkNmName(i) {
  1996. var start = i;
  1997. if (i >= tokensLength) return 0;
  1998. // start char / word
  1999. if (tokens[i].type === TokenType.HyphenMinus ||
  2000. tokens[i].type === TokenType.LowLine ||
  2001. tokens[i].type === TokenType.Identifier ||
  2002. tokens[i].type === TokenType.DecimalNumber) i++;
  2003. else return 0;
  2004. for (; i < tokensLength; i++) {
  2005. if (tokens[i].type !== TokenType.HyphenMinus &&
  2006. tokens[i].type !== TokenType.LowLine &&
  2007. tokens[i].type !== TokenType.Identifier &&
  2008. tokens[i].type !== TokenType.DecimalNumber) break;
  2009. }
  2010. tokens[start].nm_name_last = i - 1;
  2011. return i - start;
  2012. }
  2013. /**
  2014. * @returns {String}
  2015. */
  2016. function getNmName() {
  2017. var s = joinValues(pos, tokens[pos].nm_name_last);
  2018. pos = tokens[pos].nm_name_last + 1;
  2019. return s;
  2020. }
  2021. /**
  2022. * @param {Number} i Token's index number
  2023. * @returns {Number}
  2024. */
  2025. function checkNmName2(i) {
  2026. if (tokens[i].type === TokenType.Identifier) return 1;
  2027. else if (tokens[i].type !== TokenType.DecimalNumber) return 0;
  2028. i++;
  2029. return i < tokensLength && tokens[i].type === TokenType.Identifier ? 2 : 1;
  2030. }
  2031. /**
  2032. * @returns {String}
  2033. */
  2034. function getNmName2() {
  2035. var s = tokens[pos].value;
  2036. if (tokens[pos++].type === TokenType.DecimalNumber &&
  2037. pos < tokensLength &&
  2038. tokens[pos].type === TokenType.Identifier) s += tokens[pos++].value;
  2039. return s;
  2040. }
  2041. /**
  2042. * Check if token is part of an nth-selector's identifier (e.g. `2n+1`)
  2043. * @param {Number} i Token's index number
  2044. * @returns {Number}
  2045. */
  2046. function checkNth(i) {
  2047. if (i >= tokensLength) return 0;
  2048. return checkNth1(i) || checkNth2(i);
  2049. }
  2050. /**
  2051. * Check if token is part of an nth-selector's identifier in the form of
  2052. * sequence of decimals and n-s (e.g. `3`, `n`, `2n+1`)
  2053. * @param {Number} i Token's index number
  2054. * @returns {Number}
  2055. */
  2056. function checkNth1(i) {
  2057. var start = i;
  2058. for (; i < tokensLength; i++) {
  2059. if (tokens[i].type !== TokenType.DecimalNumber &&
  2060. tokens[i].value !== 'n') break;
  2061. }
  2062. if (i !== start) tokens[start].nth_last = i - 1;
  2063. return i - start;
  2064. }
  2065. /**
  2066. * Get node for nth-selector's identifier (e.g. `2n+1`)
  2067. * @returns {Array} `['nth', x]` where `x` is identifier's text
  2068. */
  2069. function getNth() {
  2070. var startPos = pos,
  2071. x;
  2072. if (tokens[pos].nth_last) {
  2073. x = joinValues(pos, tokens[pos].nth_last);
  2074. pos = tokens[pos].nth_last + 1;
  2075. } else {
  2076. x = tokens[pos++].value;
  2077. }
  2078. var token = tokens[startPos];
  2079. return new Node(NodeType.NthType, x, token.ln, token.col);
  2080. }
  2081. /**
  2082. * Check if token is part of `even` or `odd` nth-selector's identifier
  2083. * @param {Number} i Token's index number
  2084. * @returns {Number}
  2085. */
  2086. function checkNth2(i) {
  2087. return tokens[i].value === 'even' || tokens[i].value === 'odd' ? 1 : 0;
  2088. }
  2089. /**
  2090. * @param {Number} i Token's index number
  2091. * @returns {Number}
  2092. */
  2093. function checkNthf(i) {
  2094. var start = i,
  2095. l = 0;
  2096. if (tokens[i++].type !== TokenType.Colon) return 0;
  2097. // There was `:`:
  2098. l++;
  2099. if (tokens[i++].value !== 'nth' || tokens[i++].value !== '-') return 0;
  2100. // There was either `nth-` or `last-`:
  2101. l += 2;
  2102. if ('child' === tokens[i].value) {
  2103. l += 1;
  2104. } else if ('last-child' === tokens[i].value +
  2105. tokens[i + 1].value +
  2106. tokens[i + 2].value) {
  2107. l += 3;
  2108. } else if ('of-type' === tokens[i].value +
  2109. tokens[i + 1].value +
  2110. tokens[i + 2].value) {
  2111. l += 3;
  2112. } else if ('last-of-type' === tokens[i].value +
  2113. tokens[i + 1].value +
  2114. tokens[i + 2].value +
  2115. tokens[i + 3].value +
  2116. tokens[i + 4].value) {
  2117. l += 5;
  2118. } else return 0;
  2119. tokens[start + 1].nthf_last = start + l - 1;
  2120. return l;
  2121. }
  2122. /**
  2123. * @returns {String}
  2124. */
  2125. function getNthf() {
  2126. pos++;
  2127. var s = joinValues(pos, tokens[pos].nthf_last);
  2128. pos = tokens[pos].nthf_last + 1;
  2129. return s;
  2130. }
  2131. /**
  2132. * @param {Number} i Token's index number
  2133. * @returns {Number}
  2134. */
  2135. function checkNthselector(i) {
  2136. var start = i,
  2137. l;
  2138. if (i >= tokensLength) return 0;
  2139. if (l = checkNthf(i)) i += l;
  2140. else return 0;
  2141. if (tokens[i].type !== TokenType.LeftParenthesis || !tokens[i].right) return 0;
  2142. l++;
  2143. var rp = tokens[i++].right;
  2144. while (i < rp) {
  2145. if (l = checkSC(i) ||
  2146. checkUnary(i) ||
  2147. checkInterpolation(i) ||
  2148. checkNth(i)) i += l;
  2149. else return 0;
  2150. }
  2151. return rp - start + 1;
  2152. }
  2153. /**
  2154. * @returns {Array}
  2155. */
  2156. function getNthselector() {
  2157. var startPos = pos,
  2158. token = tokens[pos],
  2159. nthf = new Node(NodeType.IdentType, getNthf(), token.ln, token.col),
  2160. x = [];
  2161. x.push(nthf);
  2162. pos++;
  2163. while (tokens[pos].type !== TokenType.RightParenthesis) {
  2164. if (checkSC(pos)) x = x.concat(getSC());
  2165. else if (checkUnary(pos)) x.push(getUnary());
  2166. else if (checkInterpolation(pos)) x.push(getInterpolation());
  2167. else if (checkNth(pos)) x.push(getNth());
  2168. }
  2169. pos++;
  2170. return new Node(NodeType.NthselectorType, x, token.ln, token.col);
  2171. }
  2172. /**
  2173. * Check if token is part of a number
  2174. * @param {Number} i Token's index number
  2175. * @returns {Number} Length of number
  2176. */
  2177. function checkNumber(i) {
  2178. if (i >= tokensLength) return 0;
  2179. if (tokens[i].number_l) return tokens[i].number_l;
  2180. // `10`:
  2181. if (i < tokensLength && tokens[i].type === TokenType.DecimalNumber &&
  2182. (!tokens[i + 1] ||
  2183. (tokens[i + 1] && tokens[i + 1].type !== TokenType.FullStop)))
  2184. return (tokens[i].number_l = 1, tokens[i].number_l);
  2185. // `10.`:
  2186. if (i < tokensLength &&
  2187. tokens[i].type === TokenType.DecimalNumber &&
  2188. tokens[i + 1] && tokens[i + 1].type === TokenType.FullStop &&
  2189. (!tokens[i + 2] || (tokens[i + 2].type !== TokenType.DecimalNumber)))
  2190. return (tokens[i].number_l = 2, tokens[i].number_l);
  2191. // `.10`:
  2192. if (i < tokensLength &&
  2193. tokens[i].type === TokenType.FullStop &&
  2194. tokens[i + 1].type === TokenType.DecimalNumber)
  2195. return (tokens[i].number_l = 2, tokens[i].number_l);
  2196. // `10.10`:
  2197. if (i < tokensLength &&
  2198. tokens[i].type === TokenType.DecimalNumber &&
  2199. tokens[i + 1] && tokens[i + 1].type === TokenType.FullStop &&
  2200. tokens[i + 2] && tokens[i + 2].type === TokenType.DecimalNumber)
  2201. return (tokens[i].number_l = 3, tokens[i].number_l);
  2202. return 0;
  2203. }
  2204. /**
  2205. * Get node with number
  2206. * @returns {Array} `['number', x]` where `x` is a number converted
  2207. * to string.
  2208. */
  2209. function getNumber() {
  2210. var s = '',
  2211. startPos = pos,
  2212. l = tokens[pos].number_l;
  2213. for (var j = 0; j < l; j++) {
  2214. s += tokens[pos + j].value;
  2215. }
  2216. pos += l;
  2217. var token = tokens[startPos];
  2218. return new Node(NodeType.NumberType, s, token.ln, token.col);
  2219. }
  2220. /**
  2221. * Check if token is an operator (`/`, `,`, `:` or `=`).
  2222. * @param {Number} i Token's index number
  2223. * @returns {Number} `1` if token is an operator, otherwise `0`
  2224. */
  2225. function checkOperator(i) {
  2226. if (i >= tokensLength) return 0;
  2227. switch(tokens[i].type) {
  2228. case TokenType.Solidus:
  2229. case TokenType.Comma:
  2230. case TokenType.Colon:
  2231. case TokenType.EqualsSign:
  2232. case TokenType.EqualitySign:
  2233. case TokenType.InequalitySign:
  2234. case TokenType.LessThanSign:
  2235. case TokenType.GreaterThanSign:
  2236. case TokenType.Asterisk:
  2237. return 1;
  2238. }
  2239. return 0;
  2240. }
  2241. /**
  2242. * Get node with an operator
  2243. * @returns {Array} `['operator', x]` where `x` is an operator converted
  2244. * to string.
  2245. */
  2246. function getOperator() {
  2247. var startPos = pos,
  2248. x = tokens[pos++].value;
  2249. var token = tokens[startPos];
  2250. return new Node(NodeType.OperatorType, x, token.ln, token.col);
  2251. }
  2252. /**
  2253. * Check if token is a parent selector (`&`).
  2254. * @param {Number} i Token's index number
  2255. * @returns {Number}
  2256. */
  2257. function checkParentSelector(i) {
  2258. return i < tokensLength && tokens[i].type === TokenType.Ampersand ? 1 : 0;
  2259. }
  2260. /**
  2261. * Get node with a parent selector
  2262. * @returns {Array} `['parentSelector']`
  2263. */
  2264. function getParentSelector() {
  2265. var startPos = pos++;
  2266. var token = tokens[startPos];
  2267. return new Node(NodeType.ParentSelectorType, '&', token.ln, token.col);
  2268. }
  2269. /**
  2270. * Check if token is part of a number with percent sign (e.g. `10%`)
  2271. * @param {Number} i Token's index number
  2272. * @returns {Number}
  2273. */
  2274. function checkPercentage(i) {
  2275. var x;
  2276. if (i >= tokensLength) return 0;
  2277. x = checkNumber(i);
  2278. if (!x || i + x >= tokensLength) return 0;
  2279. return tokens[i + x].type === TokenType.PercentSign ? x + 1 : 0;
  2280. }
  2281. /**
  2282. * Get node of number with percent sign
  2283. * @returns {Array} `['percentage', ['number', x]]` where `x` is a number
  2284. * (without percent sign) converted to string.
  2285. */
  2286. function getPercentage() {
  2287. var startPos = pos,
  2288. x = [getNumber()];
  2289. pos++;
  2290. var token = tokens[startPos];
  2291. return new Node(NodeType.PercentageType, x, token.ln, token.col);
  2292. }
  2293. /**
  2294. * Check if token is part of a placeholder selector (e.g. `%abc`).
  2295. * @param {Number} i Token's index number
  2296. * @returns {Number} Length of the selector
  2297. */
  2298. function checkPlaceholder(i) {
  2299. var l;
  2300. if (i >= tokensLength) return 0;
  2301. if (tokens[i].placeholder_l) return tokens[i].placeholder_l;
  2302. if (tokens[i].type === TokenType.PercentSign && (l = checkIdent(i + 1))) {
  2303. tokens[i].placeholder_l = l + 1;
  2304. return l + 1;
  2305. } else return 0;
  2306. }
  2307. /**
  2308. * Get node with a placeholder selector
  2309. * @returns {Array} `['placeholder', ['ident', x]]` where x is a placeholder's
  2310. * identifier (without `%`, e.g. `abc`).
  2311. */
  2312. function getPlaceholder() {
  2313. var startPos = pos,
  2314. x = [];
  2315. pos++;
  2316. x.push(getIdent());
  2317. var token = tokens[startPos];
  2318. return new Node(NodeType.PlaceholderType, x, token.ln, token.col);
  2319. }
  2320. /**
  2321. * @param {Number} i Token's index number
  2322. * @returns {Number}
  2323. */
  2324. function checkProgid(i) {
  2325. var start = i,
  2326. l;
  2327. if (i >= tokensLength) return 0;
  2328. if (l = checkSC(i)) i += l;
  2329. if (joinValues2(i, 6) === 'progid:DXImageTransform.Microsoft.') i += 6;
  2330. else return 0;
  2331. if (l = checkIdent(i)) i += l;
  2332. else return 0;
  2333. if (l = checkSC(i)) i += l;
  2334. if (tokens[i].type === TokenType.LeftParenthesis) {
  2335. tokens[start].progid_end = tokens[i].right;
  2336. i = tokens[i].right + 1;
  2337. } else return 0;
  2338. return i - start;
  2339. }
  2340. /**
  2341. * @returns {Array}
  2342. */
  2343. function getProgid() {
  2344. var startPos = pos,
  2345. progid_end = tokens[pos].progid_end,
  2346. x;
  2347. x = []
  2348. .concat(getSC())
  2349. .concat([_getProgid(progid_end)]);
  2350. var token = tokens[startPos];
  2351. return new Node(NodeType.ProgidType, x, token.ln, token.col);
  2352. }
  2353. /**
  2354. * @param {Number} progid_end
  2355. * @returns {Array}
  2356. */
  2357. function _getProgid(progid_end) {
  2358. var startPos = pos,
  2359. x = joinValues(pos, progid_end);
  2360. pos = progid_end + 1;
  2361. var token = tokens[startPos];
  2362. return new Node(NodeType.RawType, x, token.ln, token.col);
  2363. }
  2364. /**
  2365. * Check if token is part of a property
  2366. * @param {Number} i Token's index number
  2367. * @returns {Number} Length of the property
  2368. */
  2369. function checkProperty(i) {
  2370. var start = i,
  2371. l;
  2372. if (i >= tokensLength) return 0;
  2373. if (l = checkVariable(i) || checkIdent(i)) i += l;
  2374. else return 0;
  2375. return i - start;
  2376. }
  2377. /**
  2378. * Get node with a property
  2379. * @returns {Array} `['property', x]`
  2380. */
  2381. function getProperty() {
  2382. var startPos = pos,
  2383. x = [];
  2384. x.push(checkVariable(pos) ? getVariable() : getIdent());
  2385. var token = tokens[startPos];
  2386. return new Node(NodeType.PropertyType, x, token.ln, token.col);
  2387. }
  2388. /**
  2389. * Check if token is a colon
  2390. * @param {Number} i Token's index number
  2391. * @returns {Number} `1` if token is a colon, otherwise `0`
  2392. */
  2393. function checkPropertyDelim(i) {
  2394. return i < tokensLength && tokens[i].type === TokenType.Colon ? 1 : 0;
  2395. }
  2396. /**
  2397. * Get node with a colon
  2398. * @returns {Array} `['propertyDelim']`
  2399. */
  2400. function getPropertyDelim() {
  2401. var startPos = pos++;
  2402. var token = tokens[startPos];
  2403. return new Node(NodeType.PropertyDelimType, ':', token.ln, token.col);
  2404. }
  2405. /**
  2406. * @param {Number} i Token's index number
  2407. * @returns {Number}
  2408. */
  2409. function checkPseudo(i) {
  2410. return checkPseudoe(i) ||
  2411. checkPseudoc(i);
  2412. }
  2413. /**
  2414. * @returns {Array}
  2415. */
  2416. function getPseudo() {
  2417. if (checkPseudoe(pos)) return getPseudoe();
  2418. if (checkPseudoc(pos)) return getPseudoc();
  2419. }
  2420. /**
  2421. * @param {Number} i Token's index number
  2422. * @returns {Number}
  2423. */
  2424. function checkPseudoe(i) {
  2425. var l;
  2426. if (i >= tokensLength || tokens[i++].type !== TokenType.Colon ||
  2427. i >= tokensLength || tokens[i++].type !== TokenType.Colon) return 0;
  2428. return (l = checkInterpolation(i) || checkIdent(i)) ? l + 2 : 0;
  2429. }
  2430. /**
  2431. * @returns {Array}
  2432. */
  2433. function getPseudoe() {
  2434. var startPos = pos,
  2435. x = [];
  2436. pos += 2;
  2437. x.push(checkInterpolation(pos) ? getInterpolation() : getIdent());
  2438. var token = tokens[startPos];
  2439. return new Node(NodeType.PseudoeType, x, token.ln, token.col);
  2440. }
  2441. /**
  2442. * @param {Number} i Token's index number
  2443. * @returns {Number}
  2444. */
  2445. function checkPseudoc(i) {
  2446. var l;
  2447. if (i >= tokensLength || tokens[i++].type !== TokenType.Colon) return 0;
  2448. return (l = checkInterpolation(i) || checkFunction(i) || checkIdent(i)) ? l + 1 : 0;
  2449. }
  2450. /**
  2451. * @returns {Array}
  2452. */
  2453. function getPseudoc() {
  2454. var startPos = pos,
  2455. x = [];
  2456. pos ++;
  2457. if (checkInterpolation(pos)) x.push(getInterpolation());
  2458. else if (checkFunction(pos)) x.push(getFunction());
  2459. else x.push(getIdent());
  2460. var token = tokens[startPos];
  2461. return new Node(NodeType.PseudocType, x, token.ln, token.col);
  2462. }
  2463. /**
  2464. * @param {Number} i Token's index number
  2465. * @returns {Number}
  2466. */
  2467. function checkRuleset(i) {
  2468. var start = i,
  2469. l;
  2470. if (i >= tokensLength) return 0;
  2471. if (tokens[start].ruleset_l) return tokens[start].ruleset_l;
  2472. while (i < tokensLength) {
  2473. if (l = checkBlock(i)) {i += l; break;}
  2474. else if (l = checkSelector(i)) i += l;
  2475. else return 0;
  2476. }
  2477. tokens[start].ruleset_l = i - start;
  2478. return i - start;
  2479. }
  2480. /**
  2481. * @returns {Array}
  2482. */
  2483. function getRuleset() {
  2484. var startPos = pos,
  2485. x = [];
  2486. while (pos < tokensLength) {
  2487. if (checkBlock(pos)) {x.push(getBlock()); break;}
  2488. else if (checkSelector(pos)) x.push(getSelector());
  2489. else break;
  2490. }
  2491. var token = tokens[startPos];
  2492. return new Node(NodeType.RulesetType, x, token.ln, token.col);
  2493. }
  2494. /**
  2495. * Check if token is marked as a space (if it's a space or a tab
  2496. * or a line break).
  2497. * @param i
  2498. * @returns {Number} Number of spaces in a row starting with the given token.
  2499. */
  2500. function checkS(i) {
  2501. return i < tokensLength && tokens[i].ws ? tokens[i].ws_last - i + 1 : 0;
  2502. }
  2503. /**
  2504. * Get node with spaces
  2505. * @returns {Array} `['s', x]` where `x` is a string containing spaces
  2506. */
  2507. function getS() {
  2508. var startPos = pos,
  2509. x = joinValues(pos, tokens[pos].ws_last);
  2510. pos = tokens[pos].ws_last + 1;
  2511. var token = tokens[startPos];
  2512. return new Node(NodeType.SType, x, token.ln, token.col);
  2513. }
  2514. /**
  2515. * Check if token is a space or a comment.
  2516. * @param {Number} i Token's index number
  2517. * @returns {Number} Number of similar (space or comment) tokens
  2518. * in a row starting with the given token.
  2519. */
  2520. function checkSC(i) {
  2521. if (!tokens[i]) return 0;
  2522. var l,
  2523. lsc = 0,
  2524. ln = tokens[i].ln;
  2525. while (i < tokensLength) {
  2526. if (tokens[i].ln !== ln) break;
  2527. if (!(l = checkS(i)) &&
  2528. !(l = checkCommentML(i)) &&
  2529. !(l = checkCommentSL(i))) break;
  2530. i += l;
  2531. lsc += l;
  2532. }
  2533. return lsc || 0;
  2534. }
  2535. /**
  2536. * Get node with spaces and comments
  2537. * @returns {Array} Array containing nodes with spaces (if there are any)
  2538. * and nodes with comments (if there are any):
  2539. * `[['s', x]*, ['comment', y]*]` where `x` is a string of spaces
  2540. * and `y` is a comment's text (without `/*` and `* /`).
  2541. */
  2542. function getSC() {
  2543. var sc = [],
  2544. ln;
  2545. if (pos >= tokensLength) return sc;
  2546. ln = tokens[pos].ln;
  2547. while (pos < tokensLength) {
  2548. if (tokens[pos].ln !== ln) break;
  2549. else if (checkS(pos)) sc.push(getS());
  2550. else if (checkCommentML(pos)) sc.push(getCommentML());
  2551. else if (checkCommentSL(pos)) sc.push(getCommentSL());
  2552. else break;
  2553. }
  2554. return sc;
  2555. }
  2556. /**
  2557. * Check if token is part of a selector
  2558. * @param {Number} i Token's index number
  2559. * @returns {Number} Length of the selector
  2560. */
  2561. function checkSelector(i) {
  2562. var start = i,
  2563. l, ln;
  2564. if (i >= tokensLength) return 0;
  2565. ln = tokens[i].ln;
  2566. while (i < tokensLength) {
  2567. if (tokens[i].ln !== ln) break;
  2568. if ((l = checkDeclDelim(i) && checkBlock(i + l)) || checkSC(i)) i += l;
  2569. if (l = checkSimpleSelector(i) || checkDelim(i)) i += l;
  2570. else break;
  2571. }
  2572. tokens[start].selector_end = i - 1;
  2573. return i - start;
  2574. }
  2575. /**
  2576. * @returns {Array}
  2577. */
  2578. function getSelector() {
  2579. var startPos = pos,
  2580. x = [],
  2581. selector_end = tokens[pos].selector_end,
  2582. ln = tokens[pos].ln;
  2583. while (pos <= selector_end) {
  2584. if (tokens[pos].ln !== ln) break;
  2585. if ((l = checkDeclDelim(pos)) && checkBlock(pos + l)) x.push(getDeclDelim());
  2586. else if (checkSC(pos)) x = x.concat(getSC());
  2587. x.push(checkDelim(pos) ? getDelim() : getSimpleSelector());
  2588. }
  2589. var token = tokens[startPos];
  2590. return new Node(NodeType.SelectorType, x, token.ln, token.col);
  2591. }
  2592. /**
  2593. * Check if token is part of a hexadecimal number (e.g. `#fff`) inside
  2594. * a simple selector
  2595. * @param {Number} i Token's index number
  2596. * @returns {Number}
  2597. */
  2598. function checkShash(i) {
  2599. var l;
  2600. if (i >= tokensLength || tokens[i].type !== TokenType.NumberSign) return 0;
  2601. return (l = checkNmName(i + 1)) ? l + 1 : 0;
  2602. }
  2603. /**
  2604. * Get node with a hexadecimal number (e.g. `#fff`) inside a simple
  2605. * selector
  2606. * @returns {Array} `['shash', x]` where `x` is a hexadecimal number
  2607. * converted to string (without `#`, e.g. `fff`)
  2608. */
  2609. function getShash() {
  2610. var startPos = pos,
  2611. x = [];
  2612. pos++;
  2613. x.push(getNmName());
  2614. var token = tokens[startPos];
  2615. return new Node(NodeType.ShashType, x, token.ln, token.col);
  2616. }
  2617. /**
  2618. * @param {Number} i Token's index number
  2619. * @returns {Number}
  2620. */
  2621. function checkSimpleSelector(i) {
  2622. if (i >= tokensLength) return 0;
  2623. var start = i,
  2624. l,
  2625. ln = tokens[i].ln;
  2626. while (i < tokensLength) {
  2627. if (tokens[i].ln !== ln) break;
  2628. if (l = checkSimpleSelector1(i)) i += l;
  2629. else break;
  2630. }
  2631. return (i - start) || 0;
  2632. }
  2633. /**
  2634. * @returns {Array}
  2635. */
  2636. function getSimpleSelector() {
  2637. var startPos = pos,
  2638. x = [],
  2639. t,
  2640. ln = tokens[pos].ln;
  2641. while (pos < tokensLength) {
  2642. if (tokens[pos].ln !== ln ||
  2643. !checkSimpleSelector1(pos)) break;
  2644. t = getSimpleSelector1();
  2645. if (typeof t.content === 'string') x.push(t);
  2646. else x = x.concat(t);
  2647. }
  2648. var token = tokens[startPos];
  2649. return new Node(NodeType.SimpleselectorType, x, token.ln, token.col);
  2650. }
  2651. /**
  2652. * @param {Number} i Token's index number
  2653. * @returns {Number}
  2654. */
  2655. function checkSimpleSelector1(i) {
  2656. var l;
  2657. if (l = checkParentSelector(i)) tokens[i].simpleselector1_child = 1;
  2658. else if (l = checkInterpolation(i)) tokens[i].simpleselector1_child = 2;
  2659. else if (l = checkNthselector(i)) tokens[i].simpleselector1_child = 3;
  2660. else if (l = checkCombinator(i)) tokens[i].simpleselector1_child = 4;
  2661. else if (l = checkAttrib(i)) tokens[i].simpleselector1_child = 5;
  2662. else if (l = checkPseudo(i)) tokens[i].simpleselector1_child = 6;
  2663. else if (l = checkShash(i)) tokens[i].simpleselector1_child = 7;
  2664. else if (l = checkAny(i)) tokens[i].simpleselector1_child = 8;
  2665. else if (l = checkSC(i)) tokens[i].simpleselector1_child = 9;
  2666. else if (l = checkNamespace(i)) tokens[i].simpleselector1_child = 10;
  2667. else if (l = checkDeepSelector(i)) tokens[i].simpleselector1_child = 11;
  2668. return l;
  2669. }
  2670. /**
  2671. * @returns {Array}
  2672. */
  2673. function getSimpleSelector1() {
  2674. var childType = tokens[pos].simpleselector1_child;
  2675. if (childType === 1) return getParentSelector();
  2676. if (childType === 2) return getInterpolation();
  2677. if (childType === 3) return getNthselector();
  2678. if (childType === 4) return getCombinator();
  2679. if (childType === 5) return getAttrib();
  2680. if (childType === 6) return getPseudo();
  2681. if (childType === 7) return getShash();
  2682. if (childType === 8) return getAny();
  2683. if (childType === 9) return getSC();
  2684. if (childType === 10) return getNamespace();
  2685. if (childType === 11) return getDeepSelector();
  2686. }
  2687. /**
  2688. * @param {Number} i Token's index number
  2689. * @returns {Number}
  2690. */
  2691. function checkSimpleSelector2(i) {
  2692. return checkParentSelector(i) ||
  2693. checkNthselector(i) ||
  2694. checkAttrib(i) ||
  2695. checkPseudo(i) ||
  2696. checkShash(i) ||
  2697. checkPlaceholder(i) ||
  2698. checkIdent(i) ||
  2699. checkClass(i);
  2700. }
  2701. /**
  2702. * @returns {Array}
  2703. */
  2704. function getSimpleSelector2() {
  2705. if (checkParentSelector(pos)) return getParentSelector();
  2706. else if (checkNthselector(pos)) return getNthselector();
  2707. else if (checkAttrib(pos)) return getAttrib();
  2708. else if (checkPseudo(pos)) return getPseudo();
  2709. else if (checkShash(pos)) return getShash();
  2710. else if (checkPlaceholder(pos)) return getPlaceholder();
  2711. else if (checkIdent(pos)) return getIdent();
  2712. else if (checkClass(pos)) return getClass();
  2713. }
  2714. /**
  2715. * Check if token is part of a string (text wrapped in quotes)
  2716. * @param {Number} i Token's index number
  2717. * @returns {Number} `1` if token is part of a string, `0` if not
  2718. */
  2719. function checkString(i) {
  2720. return i < tokensLength && (tokens[i].type === TokenType.StringSQ || tokens[i].type === TokenType.StringDQ) ? 1 : 0;
  2721. }
  2722. /**
  2723. * Get string's node
  2724. * @returns {Array} `['string', x]` where `x` is a string (including
  2725. * quotes).
  2726. */
  2727. function getString() {
  2728. var startPos = pos,
  2729. x = tokens[pos++].value;
  2730. var token = tokens[startPos];
  2731. return new Node(NodeType.StringType, x, token.ln, token.col);
  2732. }
  2733. /**
  2734. * Validate stylesheet: it should consist of any number (0 or more) of
  2735. * rulesets (sets of rules with selectors), @-rules, whitespaces or
  2736. * comments.
  2737. * @param {Number} i Token's index number
  2738. * @returns {Number}
  2739. */
  2740. function checkStylesheet(i) {
  2741. var start = i,
  2742. l;
  2743. while (i < tokensLength) {
  2744. if (l = checkSC(i) ||
  2745. checkDeclaration(i) ||
  2746. checkDeclDelim(i) ||
  2747. checkInclude(i) ||
  2748. checkMixin(i) ||
  2749. checkLoop(i) ||
  2750. checkConditionalStatement(i) ||
  2751. checkAtrule(i) ||
  2752. checkRuleset(i)) i += l;
  2753. else throwError(i);
  2754. }
  2755. return i - start;
  2756. }
  2757. /**
  2758. * @returns {Array} `['stylesheet', x]` where `x` is all stylesheet's
  2759. * nodes.
  2760. */
  2761. function getStylesheet() {
  2762. var startPos = pos,
  2763. x = [];
  2764. while (pos < tokensLength) {
  2765. if (checkSC(pos)) x = x.concat(getSC());
  2766. else if (checkRuleset(pos)) x.push(getRuleset());
  2767. else if (checkInclude(pos)) x.push(getInclude());
  2768. else if (checkMixin(pos)) x.push(getMixin());
  2769. else if (checkLoop(pos)) x.push(getLoop());
  2770. else if (checkConditionalStatement(pos)) x.push(getConditionalStatement());
  2771. else if (checkAtrule(pos)) x.push(getAtrule());
  2772. else if (checkDeclaration(pos)) x.push(getDeclaration());
  2773. else if (checkDeclDelim(pos)) x.push(getDeclDelim());
  2774. else throwError();
  2775. }
  2776. var token = tokens[startPos];
  2777. return new Node(NodeType.StylesheetType, x, token.ln, token.col);
  2778. }
  2779. /**
  2780. * @param {Number} i Token's index number
  2781. * @returns {Number}
  2782. */
  2783. function checkTset(i) {
  2784. return checkVhash(i) ||
  2785. checkAny(i) ||
  2786. checkSC(i) ||
  2787. checkOperator(i);
  2788. }
  2789. /**
  2790. * @returns {Array}
  2791. */
  2792. function getTset() {
  2793. if (checkVhash(pos)) return getVhash();
  2794. else if (checkAny(pos)) return getAny();
  2795. else if (checkSC(pos)) return getSC();
  2796. else if (checkOperator(pos)) return getOperator();
  2797. }
  2798. /**
  2799. * @param {Number} i Token's index number
  2800. * @returns {Number}
  2801. */
  2802. function checkTsets(i) {
  2803. var start = i,
  2804. l;
  2805. if (i >= tokensLength) return 0;
  2806. while (tokens[i - 1].type !== TokenType.Newline &&
  2807. (l = checkTset(i))) {
  2808. i += l;
  2809. }
  2810. return i - start;
  2811. }
  2812. /**
  2813. * @returns {Array}
  2814. */
  2815. function getTsets() {
  2816. var x = [],
  2817. t;
  2818. while (tokens[pos - 1].type !== TokenType.Newline &&
  2819. (t = getTset())) {
  2820. if (typeof t.content === 'string') x.push(t);
  2821. else x = x.concat(t);
  2822. }
  2823. return x;
  2824. }
  2825. /**
  2826. * Check if token is an unary (arithmetical) sign (`+` or `-`)
  2827. * @param {Number} i Token's index number
  2828. * @returns {Number} `1` if token is an unary sign, `0` if not
  2829. */
  2830. function checkUnary(i) {
  2831. return i < tokensLength && (tokens[i].type === TokenType.HyphenMinus || tokens[i].type === TokenType.PlusSign) ? 1 : 0;
  2832. }
  2833. /**
  2834. * Get node with an unary (arithmetical) sign (`+` or `-`)
  2835. * @returns {Array} `['unary', x]` where `x` is an unary sign
  2836. * converted to string.
  2837. */
  2838. function getUnary() {
  2839. var startPos = pos,
  2840. x = tokens[pos++].value;
  2841. var token = tokens[startPos];
  2842. return new Node(NodeType.UnaryType, x, token.ln, token.col);
  2843. }
  2844. /**
  2845. * @param {Number} i Token's index number
  2846. * @returns {Number}
  2847. */
  2848. function checkUnknown(i) {
  2849. return i < tokensLength && tokens[i].type === TokenType.CommentSL ? 1 : 0;
  2850. }
  2851. /**
  2852. * @returns {Array}
  2853. */
  2854. function getUnknown() {
  2855. var startPos = pos,
  2856. x = tokens[pos++].value;
  2857. var token = tokens[startPos];
  2858. return new Node(NodeType.UnknownType, x, token.ln, token.col);
  2859. }
  2860. /**
  2861. * Check if token is part of URI (e.g. `url('/css/styles.css')`)
  2862. * @param {Number} i Token's index number
  2863. * @returns {Number} Length of URI
  2864. */
  2865. function checkUri(i) {
  2866. var start = i;
  2867. if (i >= tokensLength || tokens[i++].value !== 'url' ||
  2868. i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)
  2869. return 0;
  2870. return tokens[i].right - start + 1;
  2871. }
  2872. /**
  2873. * Get node with URI
  2874. * @returns {Array} `['uri', x]` where `x` is URI's nodes (without `url`
  2875. * and braces, e.g. `['string', ''/css/styles.css'']`).
  2876. */
  2877. function getUri() {
  2878. var startPos = pos,
  2879. uriExcluding = {},
  2880. uri,
  2881. token,
  2882. l,
  2883. raw;
  2884. pos += 2;
  2885. uriExcluding[TokenType.Space] = 1;
  2886. uriExcluding[TokenType.Tab] = 1;
  2887. uriExcluding[TokenType.Newline] = 1;
  2888. uriExcluding[TokenType.LeftParenthesis] = 1;
  2889. uriExcluding[TokenType.RightParenthesis] = 1;
  2890. if (checkUri1(pos)) {
  2891. uri = []
  2892. .concat(getSC())
  2893. .concat([getString()])
  2894. .concat(getSC());
  2895. pos++;
  2896. } else {
  2897. uri = [].concat(getSC()),
  2898. l = checkExcluding(uriExcluding, pos),
  2899. token = tokens[pos],
  2900. raw = new Node(NodeType.RawType, joinValues(pos, pos + l), token.ln, token.col);
  2901. uri.push(raw);
  2902. pos += l + 1;
  2903. uri = uri.concat(getSC());
  2904. pos++;
  2905. }
  2906. token = tokens[startPos];
  2907. return new Node(NodeType.UriType, uri, token.ln, token.col);
  2908. }
  2909. /**
  2910. * @param {Number} i Token's index number
  2911. * @returns {Number}
  2912. */
  2913. function checkUri1(i) {
  2914. var start = i,
  2915. l;
  2916. if (i >= tokensLength) return 0;
  2917. if (l = checkSC(i)) i += l;
  2918. if (tokens[i].type !== TokenType.StringDQ && tokens[i].type !== TokenType.StringSQ) return 0;
  2919. i++;
  2920. if (l = checkSC(i)) i += l;
  2921. return i - start;
  2922. }
  2923. /**
  2924. * Check if token is part of a value
  2925. * @param {Number} i Token's index number
  2926. * @returns {Number} Length of the value
  2927. */
  2928. function checkValue(i) {
  2929. var start = i,
  2930. l, s, _i;
  2931. while (i < tokensLength) {
  2932. if (checkDeclDelim(i)) break;
  2933. if (l = checkBlock(i)) {
  2934. i += l;
  2935. break;
  2936. }
  2937. s = checkS(i);
  2938. _i = i + s;
  2939. if (l = _checkValue(_i)) i += l + s;
  2940. if (!l || checkBlock(i - l)) break;
  2941. }
  2942. return i - start;
  2943. }
  2944. /**
  2945. * @param {Number} i Token's index number
  2946. * @returns {Number}
  2947. */
  2948. function _checkValue(i) {
  2949. return checkVhash(i) ||
  2950. checkOperator(i) ||
  2951. checkImportant(i) ||
  2952. checkDefault(i) ||
  2953. checkAny(i) ||
  2954. checkInterpolation(i);
  2955. }
  2956. /**
  2957. * @returns {Array}
  2958. */
  2959. function getValue() {
  2960. var startPos = pos,
  2961. x = [],
  2962. t, _pos, s;
  2963. while (pos < tokensLength) {
  2964. s = checkS(pos);
  2965. _pos = pos + s;
  2966. if (checkDeclDelim(_pos)) break;
  2967. if (checkBlock(pos)) {
  2968. x.push(getBlock());
  2969. break;
  2970. }
  2971. if (!_checkValue(_pos)) break;
  2972. if (s) x.push(getS());
  2973. x.push(_getValue());
  2974. if (checkBlock(_pos)) break;
  2975. }
  2976. var token = tokens[startPos];
  2977. return new Node(NodeType.ValueType, x, token.ln, token.col);
  2978. }
  2979. /**
  2980. * @returns {Array}
  2981. */
  2982. function _getValue() {
  2983. if (checkVhash(pos)) return getVhash();
  2984. if (checkOperator(pos)) return getOperator();
  2985. if (checkImportant(pos)) return getImportant();
  2986. if (checkDefault(pos)) return getDefault();
  2987. if (checkAny(pos)) return getAny();
  2988. if (checkInterpolation(pos)) return getInterpolation();
  2989. }
  2990. /**
  2991. * Check if token is part of a variable
  2992. * @param {Number} i Token's index number
  2993. * @returns {Number} Length of the variable
  2994. */
  2995. function checkVariable(i) {
  2996. var l;
  2997. if (i >= tokensLength || tokens[i].type !== TokenType.DollarSign) return 0;
  2998. return (l = checkIdent(i + 1)) ? l + 1 : 0;
  2999. }
  3000. /**
  3001. * Get node with a variable
  3002. * @returns {Array} `['variable', ['ident', x]]` where `x` is
  3003. * a variable name.
  3004. */
  3005. function getVariable() {
  3006. var startPos = pos,
  3007. x = [];
  3008. pos++;
  3009. x.push(getIdent());
  3010. var token = tokens[startPos];
  3011. return new Node(NodeType.VariableType, x, token.ln, token.col);
  3012. }
  3013. /**
  3014. * Check if token is part of a variables list (e.g. `$values...`).
  3015. * @param {Number} i Token's index number
  3016. * @returns {Number}
  3017. */
  3018. function checkVariablesList(i) {
  3019. var d = 0, // number of dots
  3020. l;
  3021. if (i >= tokensLength) return 0;
  3022. if (l = checkVariable(i)) i+= l;
  3023. else return 0;
  3024. while (i < tokensLength && tokens[i].type === TokenType.FullStop) {
  3025. d++;
  3026. i++;
  3027. }
  3028. return d === 3 ? l + d : 0;
  3029. }
  3030. /**
  3031. * Get node with a variables list
  3032. * @returns {Array} `['variableslist', ['variable', ['ident', x]]]` where
  3033. * `x` is a variable name.
  3034. */
  3035. function getVariablesList() {
  3036. var startPos = pos,
  3037. x = [getVariable()];
  3038. pos += 3;
  3039. var token = tokens[startPos];
  3040. return new Node(NodeType.VariablesListType, x, token.ln, token.col);
  3041. }
  3042. /**
  3043. * Check if token is part of a hexadecimal number (e.g. `#fff`) inside
  3044. * some value
  3045. * @param {Number} i Token's index number
  3046. * @returns {Number}
  3047. */
  3048. function checkVhash(i) {
  3049. var l;
  3050. if (i >= tokensLength || tokens[i].type !== TokenType.NumberSign) return 0;
  3051. return (l = checkNmName2(i + 1)) ? l + 1 : 0;
  3052. }
  3053. /**
  3054. * Get node with a hexadecimal number (e.g. `#fff`) inside some value
  3055. * @returns {Array} `['vhash', x]` where `x` is a hexadecimal number
  3056. * converted to string (without `#`, e.g. `'fff'`).
  3057. */
  3058. function getVhash() {
  3059. var startPos = pos,
  3060. x;
  3061. pos++;
  3062. x = getNmName2();
  3063. var token = tokens[startPos];
  3064. return new Node(NodeType.VhashType, x, token.ln, token.col);
  3065. }
  3066. return function(_tokens, rule, _needInfo) {
  3067. tokens = _tokens;
  3068. needInfo = _needInfo;
  3069. tokensLength = tokens.length;
  3070. pos = 0;
  3071. return rules[rule]();
  3072. };
  3073. })();