parse.js 87 KB

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