parse.js 61 KB

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