123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688 |
- var Node = require('../node');
- var NodeType = require('../node-types');
- var TokenType = require('../token-types');
- /**
- * @type {Array}
- */
- var tokens;
- /**
- * @type {Number}
- */
- var tokensLength;
- /**
- * @type {Number}
- */
- var pos;
- var rules = {
- 'arguments': function() { return checkArguments(pos) && getArguments(); },
- 'atkeyword': function() { return checkAtkeyword(pos) && getAtkeyword(); },
- 'atruleb': function() { return checkAtruleb(pos) && getAtruleb(); },
- 'atruler': function() { return checkAtruler(pos) && getAtruler(); },
- 'atrulerq': function() { return checkAtrulerq(pos) && getAtrulerq(); },
- 'atrulers': function() { return checkAtrulers(pos) && getAtrulers(); },
- 'atrules': function() { return checkAtrules(pos) && getAtrules(); },
- 'attrib': function() { return checkAttrib(pos) && getAttrib(); },
- 'attrselector': function() { return checkAttrselector(pos) && getAttrselector(); },
- 'block': function() { return checkBlock(pos) && getBlock(); },
- 'braces': function() { return checkBraces(pos) && getBraces(); },
- 'class': function() { return checkClass(pos) && getClass(); },
- 'combinator': function() { return checkCombinator(pos) && getCombinator(); },
- 'commentML': function() { return checkCommentML(pos) && getCommentML(); },
- 'declaration': function() { return checkDeclaration(pos) && getDeclaration(); },
- 'declDelim': function() { return checkDeclDelim(pos) && getDeclDelim(); },
- 'delim': function() { return checkDelim(pos) && getDelim(); },
- 'dimension': function() { return checkDimension(pos) && getDimension(); },
- 'filter': function() { return checkFilter(pos) && getFilter(); },
- 'filterv': function() { return checkFilterv(pos) && getFilterv(); },
- 'functionExpression': function() { return checkFunctionExpression(pos) && getFunctionExpression(); },
- 'function': function() { return checkFunction(pos) && getFunction(); },
- 'ident': function() { return checkIdent(pos) && getIdent(); },
- 'important': function() { return checkImportant(pos) && getImportant(); },
- 'namespace': function() { return checkNamespace(pos) && getNamespace(); },
- 'nth': function() { return checkNth(pos) && getNth(); },
- 'nthselector': function() { return checkNthselector(pos) && getNthselector(); },
- 'number': function() { return checkNumber(pos) && getNumber(); },
- 'operator': function() { return checkOperator(pos) && getOperator(); },
- 'percentage': function() { return checkPercentage(pos) && getPercentage(); },
- 'progid': function() { return checkProgid(pos) && getProgid(); },
- 'property': function() { return checkProperty(pos) && getProperty(); },
- 'propertyDelim': function() { return checkPropertyDelim(pos) && getPropertyDelim(); },
- 'pseudoc': function() { return checkPseudoc(pos) && getPseudoc(); },
- 'pseudoe': function() { return checkPseudoe(pos) && getPseudoe(); },
- 'ruleset': function() { return checkRuleset(pos) && getRuleset(); },
- 's': function() { return checkS(pos) && getS(); },
- 'selector': function() { return checkSelector(pos) && getSelector(); },
- 'shash': function() { return checkShash(pos) && getShash(); },
- 'simpleselector': function() { return checkSimpleSelector(pos) && getSimpleSelector(); },
- 'string': function() { return checkString(pos) && getString(); },
- 'stylesheet': function() { return checkStylesheet(pos) && getStylesheet(); },
- 'unary': function() { return checkUnary(pos) && getUnary(); },
- 'uri': function() { return checkUri(pos) && getUri(); },
- 'value': function() { return checkValue(pos) && getValue(); },
- 'vhash': function() { return checkVhash(pos) && getVhash(); }
- };
- /**
- * Stop parsing and display error
- * @param {Number=} i Token's index number
- */
- function throwError(i) {
- var ln = tokens[i].ln;
- throw {line: ln, syntax: 'css'};
- }
- /**
- * @param {Object} exclude
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkExcluding(exclude, i) {
- var start = i;
- while(i < tokensLength) {
- if (exclude[tokens[i++].type]) break;
- }
- return i - start - 2;
- }
- /**
- * @param {Number} start
- * @param {Number} finish
- * @return {String}
- */
- function joinValues(start, finish) {
- var s = '';
- for (var i = start; i < finish + 1; i++) {
- s += tokens[i].value;
- }
- return s;
- }
- /**
- * @param {Number} start
- * @param {Number} num
- * @return {String}
- */
- function joinValues2(start, num) {
- if (start + num - 1 >= tokensLength) return;
- var s = '';
- for (var i = 0; i < num; i++) {
- s += tokens[start + i].value;
- }
- return s;
- }
- /////////////////////////////////////
- /////////////////////////////////////
- /////////////////////////////////////
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkAny(i) {
- var l;
- if (l = checkBraces(i)) tokens[i].any_child = 1;
- else if (l = checkString(i)) tokens[i].any_child = 2;
- else if (l = checkPercentage(i)) tokens[i].any_child = 3;
- else if (l = checkDimension(i)) tokens[i].any_child = 4;
- else if (l = checkNumber(i)) tokens[i].any_child = 5;
- else if (l = checkUri(i)) tokens[i].any_child = 6;
- else if (l = checkFunctionExpression(i)) tokens[i].any_child = 7;
- else if (l = checkFunction(i)) tokens[i].any_child = 8;
- else if (l = checkIdent(i)) tokens[i].any_child = 9;
- else if (l = checkClass(i)) tokens[i].any_child = 10;
- else if (l = checkUnary(i)) tokens[i].any_child = 11;
- return l;
- }
- /**
- * @return {Node}
- */
- function getAny() {
- var childType = tokens[pos].any_child;
- if (childType === 1) return getBraces();
- else if (childType === 2) return getString();
- else if (childType === 3) return getPercentage();
- else if (childType === 4) return getDimension();
- else if (childType === 5) return getNumber();
- else if (childType === 6) return getUri();
- else if (childType === 7) return getFunctionExpression();
- else if (childType === 8) return getFunction();
- else if (childType === 9) return getIdent();
- else if (childType === 10) return getClass();
- else if (childType === 11) return getUnary();
- }
- /**
- * Check if token is part of an @-word (e.g. `@import`, `@include`)
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkAtkeyword(i) {
- var l;
- // Check that token is `@`:
- if (i >= tokensLength ||
- tokens[i++].type !== TokenType.CommercialAt) return 0;
- return (l = checkIdent(i)) ? l + 1 : 0;
- }
- /**
- * Get node with @-word
- * @return {Node}
- */
- function getAtkeyword() {
- var type = NodeType.AtkeywordType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [];
- pos++;
- content.push(getIdent());
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of an attribute selector (e.g. `[attr]`,
- * `[attr='panda']`)
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkAttrib(i) {
- if (i >= tokensLength ||
- tokens[i].type !== TokenType.LeftSquareBracket ||
- !tokens[i].right) return 0;
- return tokens[i].right - i + 1;
- }
- /**
- * Get node with an attribute selector
- * @return {Node}
- */
- function getAttrib() {
- if (checkAttrib1(pos)) return getAttrib1();
- if (checkAttrib2(pos)) return getAttrib2();
- }
- /**
- * Check if token is part of an attribute selector of the form `[attr='value']`
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkAttrib1(i) {
- var start = i,
- l;
- if (i++ >= tokensLength) return 0;
- if (l = checkSC(i)) i += l;
- if (l = checkIdent(i)) i += l;
- else return 0;
- if (l = checkSC(i)) i += l;
- if (l = checkAttrselector(i)) i += l;
- else return 0;
- if (l = checkSC(i)) i += l;
- if (l = checkIdent(i) || checkString(i)) i += l;
- else return 0;
- if (l = checkSC(i)) i += l;
- return tokens[i].type === TokenType.RightSquareBracket ? i - start : 0;
- }
- /**
- * Get node with an attribute selector of the form `[attr='value']`
- * @return {Node}
- */
- function getAttrib1() {
- var type = NodeType.AttribType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [];
- pos++;
- content = content
- .concat(getSC())
- .concat([getIdent()])
- .concat(getSC())
- .concat([getAttrselector()])
- .concat(getSC())
- .concat([checkString(pos)? getString() : getIdent()])
- .concat(getSC());
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of an attribute selector of the form `[attr]`
- * Attribute can not be empty, e.g. `[]`.
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkAttrib2(i) {
- var start = i,
- l;
- if (i++ >= tokensLength) return 0;
- if (l = checkSC(i)) i += l;
- if (l = checkIdent(i)) i += l;
- else return 0;
- if (l = checkSC(i)) i += l;
- return tokens[i].type === TokenType.RightSquareBracket ? i - start : 0;
- }
- /**
- * Get node with an attribute selector of the form `[attr]`
- * @return {Node}
- */
- function getAttrib2() {
- var type = NodeType.AttribType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [];
- pos++;
- content = content
- .concat(getSC())
- .concat([getIdent()])
- .concat(getSC());
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of an attribute selector operator (`=`, `~=`,
- * `^=`, `$=`, `*=` or `|=`)
- * @param {Number} i Token's index number
- * @return {Number} Length of operator (`0` if token is not part of an
- * operator, `1` or `2` if it is).
- */
- function checkAttrselector(i) {
- if (i >= tokensLength) return 0;
- if (tokens[i].type === TokenType.EqualsSign) return 1;
- // TODO: Add example or remove
- if (tokens[i].type === TokenType.VerticalLine &&
- (!tokens[i + 1] || tokens[i + 1].type !== TokenType.EqualsSign))
- return 1;
- if (!tokens[i + 1] || tokens[i + 1].type !== TokenType.EqualsSign) return 0;
- switch(tokens[i].type) {
- case TokenType.Tilde:
- case TokenType.CircumflexAccent:
- case TokenType.DollarSign:
- case TokenType.Asterisk:
- case TokenType.VerticalLine:
- return 2;
- }
- return 0;
- }
- /**
- * Get node with an attribute selector operator (`=`, `~=`, `^=`, `$=`,
- * `*=` or `|=`)
- * @return {Node}
- */
- function getAttrselector() {
- var type = NodeType.AttrselectorType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = tokens[pos].value;
- pos++;
- if (tokens[pos] && tokens[pos].type === TokenType.EqualsSign)
- content += tokens[pos++].value;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is a part of an @-rule
- * @param {Number} i Token's index number
- * @return {Number} Length of @-rule
- */
- function checkAtrule(i) {
- var l;
- if (i >= tokensLength) return 0;
- // If token already has a record of being part of an @-rule,
- // return the @-rule's length:
- if (tokens[i].atrule_l !== undefined) return tokens[i].atrule_l;
- // If token is part of an @-rule, save the rule's type to token:
- if (l = checkAtruler(i)) tokens[i].atrule_type = 1; // @-rule with ruleset
- else if (l = checkAtruleb(i)) tokens[i].atrule_type = 2; // block @-rule
- else if (l = checkAtrules(i)) tokens[i].atrule_type = 3; // single-line @-rule
- else return 0;
- // If token is part of an @-rule, save the rule's length to token:
- tokens[i].atrule_l = l;
- return l;
- }
- /**
- * Get node with @-rule
- * @return {Node}
- */
- function getAtrule() {
- switch (tokens[pos].atrule_type) {
- case 1: return getAtruler(); // @-rule with ruleset
- case 2: return getAtruleb(); // block @-rule
- case 3: return getAtrules(); // single-line @-rule
- }
- }
- /**
- * Check if token is part of a block @-rule
- * @param {Number} i Token's index number
- * @return {Number} Length of the @-rule
- */
- function checkAtruleb(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkAtkeyword(i)) i += l;
- else return 0;
- if (l = checkTsets(i)) i += l;
- if (l = checkBlock(i)) i += l;
- else return 0;
- return i - start;
- }
- /**
- * Get node with a block @-rule
- * @return {Node}
- */
- function getAtruleb() {
- var type = NodeType.AtrulebType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [getAtkeyword()]
- .concat(getTsets())
- .concat([getBlock()]);
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of an @-rule with ruleset
- * @param {Number} i Token's index number
- * @return {Number} Length of the @-rule
- */
- function checkAtruler(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkAtkeyword(i)) i += l;
- else return 0;
- if (l = checkAtrulerq(i)) i += l;
- if (i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket) i++;
- else return 0;
- if (l = checkAtrulers(i)) i += l;
- if (i < tokensLength && tokens[i].type === TokenType.RightCurlyBracket) i++;
- else return 0;
- return i - start;
- }
- /**
- * Get node with an @-rule with ruleset
- * @return {Node}
- */
- function getAtruler() {
- var type = NodeType.AtrulerType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [getAtkeyword(), getAtrulerq()];
- pos++;
- content.push(getAtrulers());
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkAtrulerq(i) {
- return checkTsets(i);
- }
- /**
- * @return {Node}
- */
- function getAtrulerq() {
- var type = NodeType.AtrulerqType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = getTsets();
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkAtrulers(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkSC(i)) i += l;
- while (i < tokensLength) {
- if (l = checkSC(i)) tokens[i].atrulers_child = 1;
- else if (l = checkAtrule(i)) tokens[i].atrulers_child = 2;
- else if (l = checkRuleset(i)) tokens[i].atrulers_child = 3;
- else break;
- i += l;
- }
- tokens[i].atrulers_end = 1;
- if (l = checkSC(i)) i += l;
- return i - start;
- }
- /**
- * @return {Node}
- */
- function getAtrulers() {
- var type = NodeType.AtrulersType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = getSC();
- while (!tokens[pos].atrulers_end) {
- var childType = tokens[pos].atrulers_child;
- if (childType === 1) content = content.concat(getSC());
- else if (childType === 2) content.push(getAtrule());
- else if (childType === 3) content.push(getRuleset());
- }
- content = content.concat(getSC());
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkAtrules(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkAtkeyword(i)) i += l;
- else return 0;
- if (l = checkTsets(i)) i += l;
- return i - start;
- }
- /**
- * @return {Node}
- */
- function getAtrules() {
- var type = NodeType.AtrulesType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [getAtkeyword()].concat(getTsets());
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of a block (e.g. `{...}`).
- * @param {Number} i Token's index number
- * @return {Number} Length of the block
- */
- function checkBlock(i) {
- return i < tokensLength && tokens[i].type === TokenType.LeftCurlyBracket ?
- tokens[i].right - i + 1 : 0;
- }
- /**
- * Get node with a block
- * @return {Node}
- */
- function getBlock() {
- var type = NodeType.BlockType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [],
- end = tokens[pos++].right,
- content = [];
- while (pos < end) {
- if (checkBlockdecl(pos)) content = content.concat(getBlockdecl());
- else throwError(pos);
- }
- pos = end + 1;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of a declaration (property-value pair)
- * @param {Number} i Token's index number
- * @return {Number} Length of the declaration
- */
- function checkBlockdecl(i) {
- var l;
- if (i >= tokensLength) return 0;
- if (l = checkBlockdecl1(i)) tokens[i].bd_type = 1;
- else if (l = checkBlockdecl2(i)) tokens[i].bd_type = 2;
- else if (l = checkBlockdecl3(i)) tokens[i].bd_type = 3;
- else if (l = checkBlockdecl4(i)) tokens[i].bd_type = 4;
- else return 0;
- return l;
- }
- /**
- * @return {Array}
- */
- function getBlockdecl() {
- switch (tokens[pos].bd_type) {
- case 1: return getBlockdecl1();
- case 2: return getBlockdecl2();
- case 3: return getBlockdecl3();
- case 4: return getBlockdecl4();
- }
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkBlockdecl1(i) {
- var start = i,
- l;
- if (l = checkSC(i)) i += l;
- if (l = checkFilter(i)) tokens[i].bd_kind = 1;
- else if (l = checkDeclaration(i)) tokens[i].bd_kind = 2;
- else if (l = checkAtrule(i)) tokens[i].bd_kind = 3;
- else return 0;
- i += l;
- if (l = checkSC(i)) i += l;
- if (i < tokensLength && (l = checkDeclDelim(i))) i += l;
- else return 0;
- if (l = checkSC(i)) i += l;
- else return 0;
- return i - start;
- }
- /**
- * @return {Array}
- */
- function getBlockdecl1() {
- var sc = getSC(),
- x;
- switch (tokens[pos].bd_kind) {
- case 1:
- x = getFilter();
- break;
- case 2:
- x = getDeclaration();
- break;
- case 3:
- x = getAtrule();
- break;
- }
- return sc
- .concat([x])
- .concat(getSC())
- .concat([getDeclDelim()])
- .concat(getSC());
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkBlockdecl2(i) {
- var start = i,
- l;
- if (l = checkSC(i)) i += l;
- if (l = checkFilter(i)) tokens[i].bd_kind = 1;
- else if (l = checkDeclaration(i)) tokens[i].bd_kind = 2;
- else if (l = checkAtrule(i)) tokens[i].bd_kind = 3;
- else return 0;
- i += l;
- if (l = checkSC(i)) i += l;
- return i - start;
- }
- /**
- * @return {Array}
- */
- function getBlockdecl2() {
- var sc = getSC(),
- x;
- switch (tokens[pos].bd_kind) {
- case 1:
- x = getFilter();
- break;
- case 2:
- x = getDeclaration();
- break;
- case 3:
- x = getAtrule();
- break;
- }
- return sc
- .concat([x])
- .concat(getSC());
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkBlockdecl3(i) {
- var start = i,
- l;
- if (l = checkSC(i)) i += l;
- if (l = checkDeclDelim(i)) i += l;
- else return 0;
- if (l = checkSC(i)) i += l;
- return i - start;
- }
- /**
- * @return {Array}
- */
- function getBlockdecl3() {
- return getSC()
- .concat([getDeclDelim()])
- .concat(getSC());
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkBlockdecl4(i) {
- return checkSC(i);
- }
- /**
- * @return {Array}
- */
- function getBlockdecl4() {
- return getSC();
- }
- /**
- * Check if token is part of text inside parentheses or square brackets
- * (e.g. `(1)`)
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkBraces(i) {
- if (i >= tokensLength ||
- (tokens[i].type !== TokenType.LeftParenthesis &&
- tokens[i].type !== TokenType.LeftSquareBracket)) return 0;
- return tokens[i].right - i + 1;
- }
- /**
- * Get node with text inside parentheses or square brackets (e.g. `(1)`)
- * @return {Node}
- */
- function getBraces() {
- var type = NodeType.BracesType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- left = pos,
- right = tokens[pos++].right;
- content = [tokens[left].value, tokens[right].value]
- .concat(getTsets());
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of a class selector (e.g. `.abc`)
- * @param {Number} i Token's index number
- * @return {Number} Length of the class selector
- */
- function checkClass(i) {
- var l;
- if (i >= tokensLength) return 0;
- if (tokens[i].class_l) return tokens[i].class_l;
- if (tokens[i++].type === TokenType.FullStop && (l = checkIdent(i))) {
- tokens[i].class_l = l + 1;
- return l + 1;
- }
- return 0;
- }
- /**
- * Get node with a class selector
- * @return {Node}
- */
- function getClass() {
- var type = NodeType.ClassType,
- token = tokens[pos++],
- line = token.ln,
- column = token.col,
- content = [getIdent()];
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is a combinator (`+`, `>` or `~`)
- * @param {Number} i Token's index number
- * @return {Number} Length of the combinator
- */
- function checkCombinator(i) {
- if (i >= tokensLength) return 0;
- switch (tokens[i].type) {
- case TokenType.PlusSign:
- case TokenType.GreaterThanSign:
- case TokenType.Tilde:
- return 1;
- }
- return 0;
- }
- /**
- * Get node with a combinator (`+`, `>` or `~`)
- * @return {Node}
- */
- function getCombinator() {
- var type = NodeType.CombinatorType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = tokens[pos++].value;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is a multiline comment.
- * @param {Number} i Token's index number
- * @return {Number} `1` if token is a multiline comment, otherwise `0`
- */
- function checkCommentML(i) {
- return i < tokensLength && tokens[i].type === TokenType.CommentML ? 1 : 0;
- }
- /**
- * Get node with a multiline comment
- * @return {Node}
- */
- function getCommentML() {
- var type = NodeType.CommentMLType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = tokens[pos].value.substring(2),
- l = content.length;
- if (content.charAt(l - 2) === '*' && content.charAt(l - 1) === '/')
- content = content.substring(0, l - 2);
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of a declaration (property-value pair)
- * @param {Number} i Token's index number
- * @return {Number} Length of the declaration
- */
- function checkDeclaration(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkProperty(i)) i += l;
- else return 0;
- if (l = checkSC(i)) i += l;
- if (l = checkPropertyDelim(i)) i++;
- else return 0;
- if (l = checkSC(i)) i += l;
- if (l = checkValue(i)) i += l;
- else return 0;
- return i - start;
- }
- /**
- * Get node with a declaration
- * @return {Node}
- */
- function getDeclaration() {
- var type = NodeType.DeclarationType,
- token = tokens[pos],
- line = token.ln,
- column = token.col;
- var content = [getProperty()]
- .concat(getSC())
- .concat([getPropertyDelim()])
- .concat(getSC())
- .concat([getValue()]);
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is a semicolon
- * @param {Number} i Token's index number
- * @return {Number} `1` if token is a semicolon, otherwise `0`
- */
- function checkDeclDelim(i) {
- return i < tokensLength && tokens[i].type === TokenType.Semicolon ? 1 : 0;
- }
- /**
- * Get node with a semicolon
- * @return {Node}
- */
- function getDeclDelim() {
- var type = NodeType.DeclDelimType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = ';';
- pos++;
- return new Node(type, content, line, column);
- }
- function checkDeepSelector(i) {
- if (tokens[i + 2] &&
- tokens[i].value + tokens[i + 1].value + tokens[i + 2].value === '/deep/') {
- return 3;
- }
- }
- function getDeepSelector() {
- var _pos = pos++;
- var ident = getIdent();
- ident.content = '/deep/';
- ident.start.column -= 1;
- pos = _pos + 3;
- return ident;
- }
- /**
- * Check if token is a comma
- * @param {Number} i Token's index number
- * @return {Number} `1` if token is a comma, otherwise `0`
- */
- function checkDelim(i) {
- return i < tokensLength && tokens[i].type === TokenType.Comma ? 1 : 0;
- }
- /**
- * Get node with a comma
- * @return {Node}
- */
- function getDelim() {
- var type = NodeType.DelimType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = ',';
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of a number with dimension unit (e.g. `10px`)
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkDimension(i) {
- var ln = checkNumber(i),
- li;
- if (i >= tokensLength ||
- !ln ||
- i + ln >= tokensLength) return 0;
- return (li = checkNmName2(i + ln)) ? ln + li : 0;
- }
- /**
- * Get node of a number with dimension unit
- * @return {Node}
- */
- function getDimension() {
- var type = NodeType.DimensionType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [getNumber()];
- token = tokens[pos];
- var ident = new Node(NodeType.IdentType, getNmName2(), token.ln, token.col);
- content.push(ident);
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkFilter(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkFilterp(i)) i += l;
- else return 0;
- if (tokens[i].type === TokenType.Colon) i++;
- else return 0;
- if (l = checkFilterv(i)) i += l;
- else return 0;
- return i - start;
- }
- /**
- * @return {Node}
- */
- function getFilter() {
- var type = NodeType.FilterType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [getFilterp()];
- pos++;
- content.push(getFilterv());
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkFilterp(i) {
- var start = i,
- l,
- x;
- if (i >= tokensLength) return 0;
- if (tokens[i].value === 'filter') l = 1;
- else {
- x = joinValues2(i, 2);
- if (x === '-filter' || x === '_filter' || x === '*filter') l = 2;
- else {
- x = joinValues2(i, 4);
- if (x === '-ms-filter') l = 4;
- else return 0;
- }
- }
- tokens[start].filterp_l = l;
- i += l;
- if (checkSC(i)) i += l;
- return i - start;
- }
- /**
- * @return {Node}
- */
- function getFilterp() {
- var type = NodeType.PropertyType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content;
- token = tokens[pos];
- var ident = new Node(NodeType.IdentType, joinValues2(pos, token.filterp_l), token.ln, token.col);
- pos += token.filterp_l;
- content = [ident].concat(getSC());
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkFilterv(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkSC(i)) i += l;
- if (l = checkProgid(i)) i += l;
- else return 0;
- while (l = checkProgid(i)) {
- i += l;
- }
- tokens[start].last_progid = i;
- if (i < tokensLength && (l = checkSC(i))) i += l;
- if (i < tokensLength && (l = checkImportant(i))) i += l;
- return i - start;
- }
- /**
- * @return {Node}
- */
- function getFilterv() {
- var type = NodeType.FiltervType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [],
- last_progid = token.last_progid;
- content = content.concat(getSC());
- while (pos < last_progid) {
- content.push(getProgid());
- }
- if (checkSC(pos)) content = content.concat(getSC());
- if (pos < tokensLength && checkImportant(pos)) content.push(getImportant());
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkFunctionExpression(i) {
- var start = i;
- if (i >= tokensLength || tokens[i++].value !== 'expression' ||
- i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis) return 0;
- return tokens[i].right - start + 1;
- }
- /**
- * @return {Node}
- */
- function getFunctionExpression() {
- var type = NodeType.FunctionExpressionType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [];
- pos++;
- content.push(joinValues(pos + 1, tokens[pos].right - 1));
- pos = tokens[pos].right + 1;
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkFunction(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkIdent(i)) i +=l;
- else return 0;
- return i < tokensLength && tokens[i].type === TokenType.LeftParenthesis ?
- tokens[i].right - start + 1 : 0;
- }
- /**
- * @return {Node}
- */
- function getFunction() {
- var type = NodeType.FunctionType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- ident = getIdent(),
- content = [ident];
- content.push(ident.content === 'not' ? getNotArguments() : getArguments());
- return new Node(type, content, line, column);
- }
- /**
- * @return {Node}
- */
- function getArguments() {
- var type = NodeType.ArgumentsType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [],
- body;
- pos++;
- while (pos < tokensLength && tokens[pos].type !== TokenType.RightParenthesis) {
- if (checkDeclaration(pos)) content.push(getDeclaration());
- else if (checkArgument(pos)) {
- body = getArgument();
- if (typeof body.content === 'string') content.push(body);
- else content = content.concat(body);
- } else if (checkClass(pos)) content.push(getClass());
- else throwError(pos);
- }
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkArgument(i) {
- var l;
- if (l = checkVhash(i)) tokens[i].argument_child = 1;
- else if (l = checkAny(i)) tokens[i].argument_child = 2;
- else if (l = checkSC(i)) tokens[i].argument_child = 3;
- else if (l = checkOperator(i)) tokens[i].argument_child = 4;
- return l;
- }
- /**
- * @return {Node}
- */
- function getArgument() {
- var childType = tokens[pos].argument_child;
- if (childType === 1) return getVhash();
- else if (childType === 2) return getAny();
- else if (childType === 3) return getSC();
- else if (childType === 4) return getOperator();
- }
- /**
- * @return {Node}
- */
- function getNotArguments() {
- var type = NodeType.ArgumentsType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [];
- pos++;
- while (pos < tokensLength && tokens[pos].type !== TokenType.RightParenthesis) {
- // TODO: Remove these checks
- if (checkSimpleSelector(pos)) content.push(getSimpleSelector());
- else throwError(pos);
- }
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of an identifier
- * @param {Number} i Token's index number
- * @return {Number} Length of the identifier
- */
- function checkIdent(i) {
- var start = i,
- wasIdent,
- l;
- if (i >= tokensLength) return 0;
- // Check if token is part of an identifier starting with `_`:
- if (tokens[i].type === TokenType.LowLine) return checkIdentLowLine(i);
- // If token is a character, `-`, `$` or `*`, skip it & continue:
- if (tokens[i].type === TokenType.HyphenMinus ||
- tokens[i].type === TokenType.Identifier ||
- tokens[i].type === TokenType.DollarSign ||
- tokens[i].type === TokenType.Asterisk) i++;
- else return 0;
- // Remember if previous token's type was identifier:
- wasIdent = tokens[i - 1].type === TokenType.Identifier;
- for (; i < tokensLength; i++) {
- if (i >= tokensLength) break;
- if (tokens[i].type !== TokenType.HyphenMinus &&
- tokens[i].type !== TokenType.LowLine) {
- if (tokens[i].type !== TokenType.Identifier &&
- (tokens[i].type !== TokenType.DecimalNumber || !wasIdent)) break;
- else wasIdent = true;
- }
- }
- if (!wasIdent && tokens[start].type !== TokenType.Asterisk) return 0;
- tokens[start].ident_last = i - 1;
- return i - start;
- }
- /**
- * Check if token is part of an identifier starting with `_`
- * @param {Number} i Token's index number
- * @return {Number} Length of the identifier
- */
- function checkIdentLowLine(i) {
- var start = i;
- if (i++ >= tokensLength) return 0;
- for (; i < tokensLength; i++) {
- if (tokens[i].type !== TokenType.HyphenMinus &&
- tokens[i].type !== TokenType.DecimalNumber &&
- tokens[i].type !== TokenType.LowLine &&
- tokens[i].type !== TokenType.Identifier) break;
- }
- // Save index number of the last token of the identifier:
- tokens[start].ident_last = i - 1;
- return i - start;
- }
- /**
- * Get node with an identifier
- * @return {Node}
- */
- function getIdent() {
- var type = NodeType.IdentType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = joinValues(pos, tokens[pos].ident_last);
- pos = tokens[pos].ident_last + 1;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of `!important` word
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkImportant(i) {
- var start = i,
- l;
- if (i >= tokensLength ||
- tokens[i++].type !== TokenType.ExclamationMark) return 0;
- if (l = checkSC(i)) i += l;
- return tokens[i].value === 'important' ? i - start + 1 : 0;
- }
- /**
- * Get node with `!important` word
- * @return {Node}
- */
- function getImportant() {
- var type = NodeType.ImportantType,
- token = tokens[pos++],
- line = token.ln,
- column = token.col,
- content = getSC();
- if (!content || !content.length) content = '';
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is a namespace sign (`|`)
- * @param {Number} i Token's index number
- * @return {Number} `1` if token is `|`, `0` if not
- */
- function checkNamespace(i) {
- return i < tokensLength && tokens[i].type === TokenType.VerticalLine ? 1 : 0;
- }
- /**
- * Get node with a namespace sign
- * @return {Node}
- */
- function getNamespace() {
- var type = NodeType.NamespaceType,
- token = tokens[pos++],
- line = token.ln,
- column = token.col,
- content = '|';
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkNmName(i) {
- var start = i;
- if (i >= tokensLength) return 0;
- // start char / word
- if (tokens[i].type === TokenType.HyphenMinus ||
- tokens[i].type === TokenType.LowLine ||
- tokens[i].type === TokenType.Identifier ||
- tokens[i].type === TokenType.DecimalNumber) i++;
- else return 0;
- for (; i < tokensLength; i++) {
- if (tokens[i].type !== TokenType.HyphenMinus &&
- tokens[i].type !== TokenType.LowLine &&
- tokens[i].type !== TokenType.Identifier &&
- tokens[i].type !== TokenType.DecimalNumber) break;
- }
- tokens[start].nm_name_last = i - 1;
- return i - start;
- }
- /**
- * @return {String}
- */
- function getNmName() {
- var s = joinValues(pos, tokens[pos].nm_name_last);
- pos = tokens[pos].nm_name_last + 1;
- return s;
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkNmName2(i) {
- if (tokens[i].type === TokenType.Identifier) return 1;
- else if (tokens[i].type !== TokenType.DecimalNumber) return 0;
- i++;
- return i < tokensLength && tokens[i].type === TokenType.Identifier ? 2 : 1;
- }
- /**
- * @return {String}
- */
- function getNmName2() {
- var s = tokens[pos].value;
- if (tokens[pos++].type === TokenType.DecimalNumber &&
- pos < tokensLength &&
- tokens[pos].type === TokenType.Identifier) s += tokens[pos++].value;
- return s;
- }
- /**
- * Check if token is part of an nth-selector's identifier (e.g. `2n+1`)
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkNth(i) {
- if (i >= tokensLength) return 0;
- return checkNth1(i) || checkNth2(i);
- }
- /**
- * Check if token is part of an nth-selector's identifier in the form of
- * sequence of decimals and n-s (e.g. `3`, `n`, `2n+1`)
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkNth1(i) {
- var start = i;
- for (; i < tokensLength; i++) {
- if (tokens[i].type !== TokenType.DecimalNumber &&
- tokens[i].value !== 'n') break;
- }
- if (i !== start) tokens[start].nth_last = i - 1;
- return i - start;
- }
- /**
- * Get node for nth-selector's identifier (e.g. `2n+1`)
- * @return {Node}
- */
- function getNth() {
- var type = NodeType.NthType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content;
- if (token.nth_last) {
- content = joinValues(pos, token.nth_last);
- pos = token.nth_last + 1;
- } else {
- content = token.value;
- pos++;
- }
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of `even` or `odd` nth-selector's identifier
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkNth2(i) {
- return tokens[i].value === 'even' || tokens[i].value === 'odd' ? 1 : 0;
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkNthf(i) {
- var start = i,
- l = 0;
- if (tokens[i++].type !== TokenType.Colon) return 0;
- // There was `:`:
- l++;
- if (tokens[i++].value !== 'nth' || tokens[i++].value !== '-') return 0;
- // There was either `nth-` or `last-`:
- l += 2;
- if ('child' === tokens[i].value) {
- l += 1;
- } else if ('last-child' === tokens[i].value +
- tokens[i + 1].value +
- tokens[i + 2].value) {
- l += 3;
- } else if ('of-type' === tokens[i].value +
- tokens[i + 1].value +
- tokens[i + 2].value) {
- l += 3;
- } else if ('last-of-type' === tokens[i].value +
- tokens[i + 1].value +
- tokens[i + 2].value +
- tokens[i + 3].value +
- tokens[i + 4].value) {
- l += 5;
- } else return 0;
- tokens[start + 1].nthf_last = start + l - 1;
- return l;
- }
- /**
- * @return {String}
- */
- function getNthf() {
- pos++;
- var s = joinValues(pos, tokens[pos].nthf_last);
- pos = tokens[pos].nthf_last + 1;
- return s;
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkNthselector(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkNthf(i)) i += l;
- else return 0;
- if (tokens[i].type !== TokenType.LeftParenthesis || !tokens[i].right) return 0;
- l++;
- var rp = tokens[i++].right;
- while (i < rp) {
- if (l = checkSC(i)) tokens[i].nthselector_child = 1;
- else if (l = checkUnary(i)) tokens[i].nthselector_child = 2;
- else if (l = checkNth(i)) tokens[i].nthselector_child = 3;
- else return 0;
- i += l;
- }
- return rp - start + 1;
- }
- /**
- * @return {Node}
- */
- function getNthselector() {
- var type = NodeType.NthselectorType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [];
- var nthf = new Node(NodeType.IdentType, getNthf(), line, column);
- content.push(nthf);
- pos++;
- while (tokens[pos].type !== TokenType.RightParenthesis) {
- var childType = tokens[pos].nthselector_child;
- if (childType === 1) content = content.concat(getSC());
- else if (childType === 2) content.push(getUnary());
- else if (childType === 3) content.push(getNth());
- }
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of a number
- * @param {Number} i Token's index number
- * @return {Number} Length of number
- */
- function checkNumber(i) {
- if (i >= tokensLength) return 0;
- if (tokens[i].number_l) return tokens[i].number_l;
- // `10`:
- if (i < tokensLength && tokens[i].type === TokenType.DecimalNumber &&
- (!tokens[i + 1] ||
- (tokens[i + 1] && tokens[i + 1].type !== TokenType.FullStop)))
- return (tokens[i].number_l = 1, tokens[i].number_l);
- // `10.`:
- if (i < tokensLength &&
- tokens[i].type === TokenType.DecimalNumber &&
- tokens[i + 1] && tokens[i + 1].type === TokenType.FullStop &&
- (!tokens[i + 2] || (tokens[i + 2].type !== TokenType.DecimalNumber)))
- return (tokens[i].number_l = 2, tokens[i].number_l);
- // `.10`:
- if (i < tokensLength &&
- tokens[i].type === TokenType.FullStop &&
- tokens[i + 1].type === TokenType.DecimalNumber)
- return (tokens[i].number_l = 2, tokens[i].number_l);
- // `10.10`:
- if (i < tokensLength &&
- tokens[i].type === TokenType.DecimalNumber &&
- tokens[i + 1] && tokens[i + 1].type === TokenType.FullStop &&
- tokens[i + 2] && tokens[i + 2].type === TokenType.DecimalNumber)
- return (tokens[i].number_l = 3, tokens[i].number_l);
- return 0;
- }
- /**
- * Get node with number
- * @return {Node}
- */
- function getNumber() {
- var type = NodeType.NumberType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = '',
- l = tokens[pos].number_l;
- for (var j = 0; j < l; j++) {
- content += tokens[pos + j].value;
- }
- pos += l;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is an operator (`/`, `,`, `:` or `=`).
- * @param {Number} i Token's index number
- * @return {Number} `1` if token is an operator, otherwise `0`
- */
- function checkOperator(i) {
- if (i >= tokensLength) return 0;
- switch(tokens[i].type) {
- case TokenType.Solidus:
- case TokenType.Comma:
- case TokenType.Colon:
- case TokenType.EqualsSign:
- return 1;
- }
- return 0;
- }
- /**
- * Get node with an operator
- * @return {Node}
- */
- function getOperator() {
- var type = NodeType.OperatorType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = token.value;
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of a number with percent sign (e.g. `10%`)
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkPercentage(i) {
- var x;
- if (i >= tokensLength) return 0;
- x = checkNumber(i);
- if (!x || i + x >= tokensLength) return 0;
- return tokens[i + x].type === TokenType.PercentSign ? x + 1 : 0;
- }
- /**
- * Get node of number with percent sign
- * @return {Node}
- */
- function getPercentage() {
- var type = NodeType.PercentageType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [getNumber()];
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkProgid(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkSC(i)) i += l;
- if (joinValues2(i, 6) === 'progid:DXImageTransform.Microsoft.') i += 6;
- else return 0;
- if (l = checkIdent(i)) i += l;
- else return 0;
- if (l = checkSC(i)) i += l;
- if (tokens[i].type === TokenType.LeftParenthesis) {
- tokens[start].progid_end = tokens[i].right;
- i = tokens[i].right + 1;
- } else return 0;
- if (l = checkSC(i)) i += l;
- return i - start;
- }
- /**
- * @return {Node}
- */
- function getProgid() {
- var type = NodeType.ProgidType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- progid_end = token.progid_end,
- content = []
- .concat(getSC())
- .concat([_getProgid(progid_end)])
- .concat(getSC());
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} progid_end
- * @return {Node}
- */
- function _getProgid(progid_end) {
- var type = NodeType.RawType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = joinValues(pos, progid_end);
- pos = progid_end + 1;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of a property
- * @param {Number} i Token's index number
- * @return {Number} Length of the property
- */
- function checkProperty(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkIdent(i)) i += l;
- else return 0;
- return i - start;
- }
- /**
- * Get node with a property
- * @return {Node}
- */
- function getProperty() {
- var type = NodeType.PropertyType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [getIdent()];
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is a colon
- * @param {Number} i Token's index number
- * @return {Number} `1` if token is a colon, otherwise `0`
- */
- function checkPropertyDelim(i) {
- return i < tokensLength && tokens[i].type === TokenType.Colon ? 1 : 0;
- }
- /**
- * Get node with a colon
- * @return {Node}
- */
- function getPropertyDelim() {
- var type = NodeType.PropertyDelimType,
- token = tokens[pos++],
- line = token.ln,
- column = token.col,
- content = ':';
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkPseudo(i) {
- return checkPseudoe(i) ||
- checkPseudoc(i);
- }
- /**
- * @return {Node}
- */
- function getPseudo() {
- if (checkPseudoe(pos)) return getPseudoe();
- if (checkPseudoc(pos)) return getPseudoc();
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkPseudoe(i) {
- var l;
- if (i >= tokensLength || tokens[i++].type !== TokenType.Colon ||
- i >= tokensLength || tokens[i++].type !== TokenType.Colon) return 0;
- return (l = checkIdent(i)) ? l + 2 : 0;
- }
- /**
- * @return {Node}
- */
- function getPseudoe() {
- var type = NodeType.PseudoeType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [];
- pos += 2;
- content.push(getIdent());
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkPseudoc(i) {
- var l;
- if (i >= tokensLength || tokens[i++].type !== TokenType.Colon) return 0;
- if (l = checkFunction(i)) tokens[i].pseudoc_child = 1;
- else if (l = checkIdent(i)) tokens[i].pseudoc_child = 2;
- else return 0;
- return l + 1;
- }
- /**
- * @return {Node}
- */
- function getPseudoc() {
- var type = NodeType.PseudocType,
- token = tokens[pos++],
- line = token.ln,
- column = token.col,
- content = [];
- var childType = tokens[pos].pseudoc_child;
- if (childType === 1) content.push(getFunction());
- else content.push(getIdent());
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkRuleset(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (tokens[start].ruleset_l) return tokens[start].ruleset_l;
- while (i < tokensLength) {
- if (l = checkBlock(i)) {
- tokens[i].ruleset_child = 1;
- i += l;
- break;
- } else if (l = checkSelector(i)) {
- tokens[i].ruleset_child = 2;
- i += l;
- } else return 0;
- }
- tokens[start].ruleset_l = i - start;
- return i - start;
- }
- /**
- * @return {Node}
- */
- function getRuleset() {
- var type = NodeType.RulesetType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [];
- while (pos < tokensLength) {
- var childType = tokens[pos].ruleset_child;
- if (childType === 1) { content.push(getBlock()); break; }
- else if (childType === 2) content.push(getSelector());
- else break;
- }
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is marked as a space (if it's a space or a tab
- * or a line break).
- * @param i
- * @return {Number} Number of spaces in a row starting with the given token.
- */
- function checkS(i) {
- return i < tokensLength && tokens[i].ws ? tokens[i].ws_last - i + 1 : 0;
- }
- /**
- * Get node with spaces
- * @return {Node}
- */
- function getS() {
- var type = NodeType.SType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = joinValues(pos, tokens[pos].ws_last);
- pos = tokens[pos].ws_last + 1;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is a space or a comment.
- * @param {Number} i Token's index number
- * @return {Number} Number of similar (space or comment) tokens
- * in a row starting with the given token.
- */
- function checkSC(i) {
- var l,
- lsc = 0;
- while (i < tokensLength) {
- if (l = checkS(i)) tokens[i].sc_child = 1;
- else if (l = checkCommentML(i)) tokens[i].sc_child = 2;
- else break;
- i += l;
- lsc += l;
- }
- return lsc || 0;
- }
- /**
- * Get node with spaces and comments
- * @return {Array}
- */
- function getSC() {
- var sc = [];
- if (pos >= tokensLength) return sc;
- while (pos < tokensLength) {
- var childType = tokens[pos].sc_child;
- if (childType === 1) sc.push(getS());
- else if (childType === 2) sc.push(getCommentML());
- else break;
- }
- return sc;
- }
- /**
- * Check if token is part of a selector
- * @param {Number} i Token's index number
- * @return {Number} Length of the selector
- */
- function checkSelector(i) {
- var start = i,
- l;
- while (i < tokensLength) {
- if (l = checkDelim(i)) tokens[i].selector_child = 1;
- else if (l = checkSimpleSelector(i)) tokens[i].selector_child = 2;
- else break;
- i += l;
- }
- if (i !== start) tokens[start].selector_end = i - 1;
- return i - start;
- }
- /**
- * @return {Node}
- */
- function getSelector() {
- var type = NodeType.SelectorType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [],
- selector_end = token.selector_end;
- while (pos <= selector_end) {
- var childType = tokens[pos].selector_child;
- if (childType === 1) content.push(getDelim());
- else if (childType === 2) content.push(getSimpleSelector());
- }
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of a hexadecimal number (e.g. `#fff`) inside
- * a simple selector
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkShash(i) {
- var l;
- if (i >= tokensLength || tokens[i].type !== TokenType.NumberSign) return 0;
- return (l = checkNmName(i + 1)) ? l + 1 : 0;
- }
- /**
- * Get node with a hexadecimal number (e.g. `#fff`) inside a simple
- * selector
- * @return {Node}
- */
- function getShash() {
- var type = NodeType.ShashType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [];
- pos++;
- content.push(getNmName());
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkSimpleSelector(i) {
- var start = i,
- l;
- while (i < tokensLength) {
- if (l = checkSimpleSelector1(i)) i += l;
- else break;
- }
- tokens[start].simpleselector_end = i;
- return i - start;
- }
- /**
- * @return {Node}
- */
- function getSimpleSelector() {
- var type = NodeType.SimpleselectorType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [],
- end = token.simpleselector_end,
- t;
- while (pos < end) {
- t = getSimpleSelector1();
- if (typeof t.content === 'string') content.push(t);
- else content = content.concat(t);
- }
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkSimpleSelector1(i) {
- var l;
- if (l = checkNthselector(i)) tokens[i].simpleselector1_child = 1;
- else if (l = checkCombinator(i)) tokens[i].simpleselector1_child = 2;
- else if (l = checkAttrib(i)) tokens[i].simpleselector1_child = 3;
- else if (l = checkPseudo(i)) tokens[i].simpleselector1_child = 4;
- else if (l = checkShash(i)) tokens[i].simpleselector1_child = 5;
- else if (l = checkAny(i)) tokens[i].simpleselector1_child = 6;
- else if (l = checkSC(i)) tokens[i].simpleselector1_child = 7;
- else if (l = checkNamespace(i)) tokens[i].simpleselector1_child = 8;
- else if (l = checkDeepSelector(i)) tokens[i].simpleselector1_child = 9;
- return l;
- }
- /**
- * @return {Node}
- */
- function getSimpleSelector1() {
- var childType = tokens[pos].simpleselector1_child;
- if (childType === 1) return getNthselector();
- else if (childType === 2) return getCombinator();
- else if (childType === 3) return getAttrib();
- else if (childType === 4) return getPseudo();
- else if (childType === 5) return getShash();
- else if (childType === 6) return getAny();
- else if (childType === 7) return getSC();
- else if (childType === 8) return getNamespace();
- else if (childType === 9) return getDeepSelector();
- }
- /**
- * Check if token is part of a string (text wrapped in quotes)
- * @param {Number} i Token's index number
- * @return {Number} `1` if token is part of a string, `0` if not
- */
- function checkString(i) {
- return i < tokensLength && (tokens[i].type === TokenType.StringSQ || tokens[i].type === TokenType.StringDQ) ? 1 : 0;
- }
- /**
- * Get string's node
- * @return {Array} `['string', x]` where `x` is a string (including
- * quotes).
- */
- function getString() {
- var type = NodeType.StringType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = token.value;
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Validate stylesheet: it should consist of any number (0 or more) of
- * rulesets (sets of rules with selectors), @-rules, whitespaces or
- * comments.
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkStylesheet(i) {
- var start = i,
- l;
- // Check every token:
- while (i < tokensLength) {
- if (l = checkSC(i)) tokens[i].stylesheet_child = 1;
- else if (l = checkRuleset(i)) tokens[i].stylesheet_child = 2;
- else if (l = checkAtrule(i)) tokens[i].stylesheet_child = 3;
- else if (l = checkDeclDelim(i)) tokens[i].stylesheet_child = 4;
- else throwError(i);
- i += l;
- }
- return i - start;
- }
- /**
- * @return {Array} `['stylesheet', x]` where `x` is all stylesheet's
- * nodes.
- */
- function getStylesheet() {
- var type = NodeType.StylesheetType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = [],
- childType;
- while (pos < tokensLength) {
- childType = tokens[pos].stylesheet_child;
- if (childType === 1) content = content.concat(getSC());
- else if (childType === 2) content.push(getRuleset());
- else if (childType === 3) content.push(getAtrule());
- else if (childType === 4) content.push(getDeclDelim());
- }
- return new Node(type, content, line, column);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkTset(i) {
- var l;
- if (l = checkVhash(i)) tokens[i].tset_child = 1;
- else if (l = checkAny(i)) tokens[i].tset_child = 2;
- else if (l = checkSC(i)) tokens[i].tset_child = 3;
- else if (l = checkOperator(i)) tokens[i].tset_child = 4;
- return l;
- }
- /**
- * @return {Array}
- */
- function getTset() {
- var childType = tokens[pos].tset_child;
- if (childType === 1) return getVhash();
- else if (childType === 2) return getAny();
- else if (childType === 3) return getSC();
- else if (childType === 4) return getOperator();
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkTsets(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- while (l = checkTset(i)) {
- i += l;
- }
- return i - start;
- }
- /**
- * @return {Array}
- */
- function getTsets() {
- var x = [],
- t;
- while (checkTset(pos)) {
- t = getTset();
- if (typeof t.content === 'string') x.push(t);
- else x = x.concat(t);
- }
- return x;
- }
- /**
- * Check if token is an unary (arithmetical) sign (`+` or `-`)
- * @param {Number} i Token's index number
- * @return {Number} `1` if token is an unary sign, `0` if not
- */
- function checkUnary(i) {
- return i < tokensLength && (tokens[i].type === TokenType.HyphenMinus || tokens[i].type === TokenType.PlusSign) ? 1 : 0;
- }
- /**
- * Get node with an unary (arithmetical) sign (`+` or `-`)
- * @return {Array} `['unary', x]` where `x` is an unary sign
- * converted to string.
- */
- function getUnary() {
- var type = NodeType.UnaryType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content = token.value;
- pos++;
- return new Node(type, content, line, column);
- }
- /**
- * Check if token is part of URI (e.g. `url('/css/styles.css')`)
- * @param {Number} i Token's index number
- * @return {Number} Length of URI
- */
- function checkUri(i) {
- var start = i;
- if (i >= tokensLength || tokens[i].value !== 'url') return 0;
- i += 1;
- if (i >= tokensLength || tokens[i].type !== TokenType.LeftParenthesis)
- return 0;
- return tokens[i].right - start + 1;
- }
- /**
- * Get node with URI
- * @return {Array} `['uri', x]` where `x` is URI's nodes (without `url`
- * and braces, e.g. `['string', ''/css/styles.css'']`).
- */
- function getUri() {
- var startPos = pos,
- uriExcluding = {},
- uri,
- l,
- raw;
- var rawContent, t;
- pos += 2;
- uriExcluding[TokenType.Space] = 1;
- uriExcluding[TokenType.Tab] = 1;
- uriExcluding[TokenType.Newline] = 1;
- uriExcluding[TokenType.LeftParenthesis] = 1;
- uriExcluding[TokenType.RightParenthesis] = 1;
- if (checkUri1(pos)) {
- uri = []
- .concat(getSC())
- .concat([getString()])
- .concat(getSC());
- pos++;
- } else {
- uri = checkSC(pos) ? getSC() : [];
- l = checkExcluding(uriExcluding, pos),
- rawContent = joinValues(pos, pos + l);
- t = tokens[pos];
- raw = new Node(NodeType.RawType, rawContent, t.ln, t.col);
- uri.push(raw);
- pos += l + 1;
- if (checkSC(pos)) uri = uri.concat(getSC());
- pos++;
- }
- t = tokens[startPos];
- return new Node(NodeType.UriType, uri, t.ln, t.col);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkUri1(i) {
- var start = i,
- l;
- if (i >= tokensLength) return 0;
- if (l = checkSC(i)) i += l;
- if (tokens[i].type !== TokenType.StringDQ && tokens[i].type !== TokenType.StringSQ) return 0;
- i++;
- if (l = checkSC(i)) i += l;
- return i - start;
- }
- /**
- * Check if token is part of a value
- * @param {Number} i Token's index number
- * @return {Number} Length of the value
- */
- function checkValue(i) {
- var start = i,
- l, s, _i;
- while (i < tokensLength) {
- s = checkSC(i);
- _i = i + s;
- if (l = _checkValue(_i)) i += l + s;
- else break;
- }
- tokens[start].value_end = i;
- return i - start;
- }
- /**
- * @return {Array}
- */
- function getValue() {
- var startPos = pos,
- end = tokens[pos].value_end,
- x = [],
- s, _pos;
- while (pos < end) {
- if (tokens[pos].value_child) x.push(_getValue());
- else x = x.concat(getSC());
- }
- var t = tokens[startPos];
- return new Node(NodeType.ValueType, x, t.ln, t.col);
- }
- /**
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function _checkValue(i) {
- var l;
- if (l = checkVhash(i)) tokens[i].value_child = 1;
- else if (l = checkAny(i)) tokens[i].value_child = 2;
- else if (l = checkOperator(i)) tokens[i].value_child = 3;
- else if (l = checkImportant(i)) tokens[i].value_child = 4;
- return l;
- }
- /**
- * @return {Array}
- */
- function _getValue() {
- var childType = tokens[pos].value_child;
- if (childType === 1) return getVhash();
- else if (childType === 2) return getAny();
- else if (childType === 3) return getOperator();
- else if (childType === 4) return getImportant();
- }
- /**
- * Check if token is part of a hexadecimal number (e.g. `#fff`) inside
- * some value
- * @param {Number} i Token's index number
- * @return {Number}
- */
- function checkVhash(i) {
- var l;
- if (i >= tokensLength || tokens[i].type !== TokenType.NumberSign) return 0;
- return (l = checkNmName2(i + 1)) ? l + 1 : 0;
- }
- /**
- * Get node with a hexadecimal number (e.g. `#fff`) inside some value
- * @return {Array} `['vhash', x]` where `x` is a hexadecimal number
- * converted to string (without `#`, e.g. `'fff'`).
- */
- function getVhash() {
- var type = NodeType.VhashType,
- token = tokens[pos],
- line = token.ln,
- column = token.col,
- content;
- pos++;
- content = getNmName2();
- return new Node(type, content, line, column);
- }
- module.exports = function(_tokens, rule) {
- tokens = _tokens;
- tokensLength = tokens.length;
- pos = 0;
- return rules[rule]();
- };
|