parse.js 94 KB

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