UNPKG

15.6 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
5 * This code may only be used under the BSD style license found at
6 * http://polymer.github.io/LICENSE.txt The complete set of authors may be found
7 * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may
8 * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by
9 * Google as part of the polymer project is also subject to an additional IP
10 * rights grant found at http://polymer.github.io/PATENTS.txt
11 */
12Object.defineProperty(exports, "__esModule", { value: true });
13const chai_1 = require("chai");
14const shady_css_1 = require("../shady-css");
15const ast_iterator_1 = require("../shady-css/ast-iterator");
16const fixtures = require("./fixtures");
17const test_node_factory_1 = require("./test-node-factory");
18chai_1.use(require('chai-subset'));
19describe('Parser', () => {
20 let parser;
21 let nodeFactory;
22 beforeEach(() => {
23 parser = new shady_css_1.Parser();
24 nodeFactory = new test_node_factory_1.TestNodeFactory();
25 });
26 describe('when parsing css', () => {
27 it('can parse a basic ruleset', () => {
28 chai_1.expect(parser.parse(fixtures.basicRuleset))
29 .to.be.containSubset(nodeFactory.stylesheet([
30 nodeFactory.ruleset('body', nodeFactory.rulelist([
31 nodeFactory.declaration('margin', nodeFactory.expression('0')),
32 nodeFactory.declaration('padding', nodeFactory.expression('0px'))
33 ]))
34 ]));
35 });
36 it('can parse at rules', () => {
37 chai_1.expect(parser.parse(fixtures.atRules))
38 .to.containSubset(nodeFactory.stylesheet([
39 nodeFactory.atRule('import', 'url(\'foo.css\')', undefined),
40 nodeFactory.atRule('font-face', '', nodeFactory.rulelist([nodeFactory.declaration('font-family', nodeFactory.expression('foo'))])),
41 nodeFactory.atRule('charset', '\'foo\'', undefined)
42 ]));
43 });
44 it('can parse keyframes', () => {
45 chai_1.expect(parser.parse(fixtures.keyframes))
46 .to.containSubset(nodeFactory.stylesheet([
47 nodeFactory.atRule('keyframes', 'foo', nodeFactory.rulelist([
48 nodeFactory.ruleset('from', nodeFactory.rulelist([nodeFactory.declaration('fiz', nodeFactory.expression('0%'))])),
49 nodeFactory.ruleset('99.9%', nodeFactory.rulelist([
50 nodeFactory.declaration('fiz', nodeFactory.expression('100px')),
51 nodeFactory.declaration('buz', nodeFactory.expression('true'))
52 ]))
53 ]))
54 ]));
55 });
56 it('can parse custom properties', () => {
57 chai_1.expect(parser.parse(fixtures.customProperties))
58 .to.containSubset(nodeFactory.stylesheet([nodeFactory.ruleset(':root', nodeFactory.rulelist([
59 nodeFactory.declaration('--qux', nodeFactory.expression('vim')),
60 nodeFactory.declaration('--foo', nodeFactory.rulelist([nodeFactory.declaration('bar', nodeFactory.expression('baz'))]))
61 ]))]));
62 });
63 it('can parse declarations with no value', () => {
64 chai_1.expect(parser.parse(fixtures.declarationsWithNoValue))
65 .to.containSubset(nodeFactory.stylesheet([
66 nodeFactory.declaration('foo', undefined),
67 nodeFactory.declaration('bar 20px', undefined),
68 nodeFactory.ruleset('div', nodeFactory.rulelist([nodeFactory.declaration('baz', undefined)]))
69 ]));
70 });
71 it('can parse minified rulelists', () => {
72 chai_1.expect(parser.parse(fixtures.minifiedRuleset))
73 .to.containSubset(nodeFactory.stylesheet([
74 nodeFactory.ruleset('.foo', nodeFactory.rulelist([nodeFactory.declaration('bar', nodeFactory.expression('baz'))])),
75 nodeFactory.ruleset('div .qux', nodeFactory.rulelist([nodeFactory.declaration('vim', nodeFactory.expression('fet'))]))
76 ]));
77 });
78 it('can parse psuedo rulesets', () => {
79 chai_1.expect(parser.parse(fixtures.psuedoRuleset))
80 .to.containSubset(nodeFactory.stylesheet([nodeFactory.ruleset('.foo:bar:not(#rif)', nodeFactory.rulelist([nodeFactory.declaration('baz', nodeFactory.expression('qux'))]))]));
81 });
82 it('can parse rulelists with data URIs', () => {
83 chai_1.expect(parser.parse(fixtures.dataUriRuleset))
84 .to.containSubset(nodeFactory.stylesheet([nodeFactory.ruleset('.foo', nodeFactory.rulelist([nodeFactory.declaration('bar', nodeFactory.expression('url(qux;gib)'))]))]));
85 });
86 it('can parse pathological comments', () => {
87 chai_1.expect(parser.parse(fixtures.pathologicalComments))
88 .to.containSubset(nodeFactory.stylesheet([
89 nodeFactory.ruleset('.foo', nodeFactory.rulelist([nodeFactory.declaration('bar', nodeFactory.expression('/*baz*/vim'))])),
90 nodeFactory.comment('/* unclosed\n@fiz {\n --huk: {\n /* buz */'),
91 nodeFactory.declaration('baz', nodeFactory.expression('lur')),
92 nodeFactory.discarded('};'),
93 nodeFactory.discarded('}'),
94 nodeFactory.atRule('gak', 'wiz', undefined)
95 ]));
96 });
97 it('disregards extra semi-colons', () => {
98 chai_1.expect(parser.parse(fixtures.extraSemicolons))
99 .to.containSubset(nodeFactory.stylesheet([
100 nodeFactory.ruleset(':host', nodeFactory.rulelist([
101 nodeFactory.declaration('margin', nodeFactory.expression('0')),
102 nodeFactory.discarded(';;'),
103 nodeFactory.declaration('padding', nodeFactory.expression('0')),
104 nodeFactory.discarded(';'),
105 nodeFactory.discarded(';'),
106 nodeFactory.declaration('display', nodeFactory.expression('block')),
107 ])),
108 nodeFactory.discarded(';')
109 ]));
110 });
111 });
112 describe('when extracting ranges', () => {
113 it('extracts the correct ranges for discarded nodes', () => {
114 const ast = parser.parse(fixtures.extraSemicolons);
115 const nodes = getNodesOfType(ast, 'discarded');
116 const rangeSubStrings = Array.from(nodes).map((n) => {
117 return fixtures.extraSemicolons.substring(n.range.start, n.range.end);
118 });
119 chai_1.expect(rangeSubStrings).to.be.deep.equal([';;', ';', ';', ';']);
120 });
121 it('extracts the correct ranges for expression nodes', () => {
122 const ast = parser.parse(fixtures.basicRuleset);
123 const nodes = getNodesOfType(ast, 'expression');
124 const rangeSubStrings = Array.from(nodes).map((n) => {
125 return fixtures.basicRuleset.substring(n.range.start, n.range.end);
126 });
127 chai_1.expect(rangeSubStrings).to.be.deep.equal(['0', '0px']);
128 });
129 it('extracts the correct ranges for declarations', () => {
130 const expectDeclarationRanges = (cssText, expectedRangeStrings, expectedNameRangeStrings) => {
131 const ast = parser.parse(cssText);
132 const nodes = Array.from(getNodesOfType(ast, 'declaration'));
133 const rangeStrings = nodes.map((n) => {
134 return cssText.substring(n.range.start, n.range.end);
135 });
136 const nameRangeStrings = nodes.map((n) => {
137 return cssText.substring(n.nameRange.start, n.nameRange.end);
138 });
139 chai_1.expect(rangeStrings).to.be.deep.equal(expectedRangeStrings);
140 chai_1.expect(nameRangeStrings).to.be.deep.equal(expectedNameRangeStrings);
141 };
142 expectDeclarationRanges(fixtures.basicRuleset, ['margin: 0;', 'padding: 0px'], ['margin', 'padding']);
143 expectDeclarationRanges(fixtures.atRules, ['font-family: foo;'], ['font-family']);
144 expectDeclarationRanges(fixtures.keyframes, ['fiz: 0%;', 'fiz: 100px;', 'buz: true;'], ['fiz', 'fiz', 'buz']);
145 expectDeclarationRanges(fixtures.customProperties, ['--qux: vim;', '--foo: {\n bar: baz;\n };', 'bar: baz;'], ['--qux', '--foo', 'bar']);
146 expectDeclarationRanges(fixtures.extraSemicolons, [
147 'margin: 0;',
148 'padding: 0;',
149 'display: block;',
150 ], ['margin', 'padding', 'display']);
151 expectDeclarationRanges(fixtures.declarationsWithNoValue, ['foo;', 'bar 20px;', 'baz;'], ['foo', 'bar 20px', 'baz']);
152 expectDeclarationRanges(fixtures.minifiedRuleset, ['bar:baz', 'vim:fet;'], ['bar', 'vim']);
153 expectDeclarationRanges(fixtures.psuedoRuleset, ['baz:qux'], ['baz']);
154 expectDeclarationRanges(fixtures.dataUriRuleset, ['bar:url(qux;gib)'], ['bar']);
155 expectDeclarationRanges(fixtures.pathologicalComments, ['bar: /*baz*/vim;', 'baz: lur;'], ['bar', 'baz']);
156 });
157 it('extracts the correct ranges for rulesets', () => {
158 const expectRulesetRanges = (cssText, expectedRangeStrings, expectedSelectorRangeStrings) => {
159 const ast = parser.parse(cssText);
160 const nodes = Array.from(getNodesOfType(ast, 'ruleset'));
161 const rangeStrings = nodes.map((n) => {
162 return cssText.substring(n.range.start, n.range.end);
163 });
164 const selectorRangeStrings = nodes.map((n) => {
165 return cssText.substring(n.selectorRange.start, n.selectorRange.end);
166 });
167 chai_1.expect(rangeStrings).to.be.deep.equal(expectedRangeStrings);
168 chai_1.expect(selectorRangeStrings)
169 .to.be.deep.equal(expectedSelectorRangeStrings);
170 };
171 expectRulesetRanges(fixtures.basicRuleset, [`body {\n margin: 0;\n padding: 0px\n}`], ['body']);
172 expectRulesetRanges(fixtures.atRules, [], []);
173 expectRulesetRanges(fixtures.keyframes, [
174 'from {\n fiz: 0%;\n }',
175 '99.9% {\n fiz: 100px;\n buz: true;\n }'
176 ], ['from', '99.9%']);
177 expectRulesetRanges(fixtures.customProperties, [':root {\n --qux: vim;\n --foo: {\n bar: baz;\n };\n}'], [':root']);
178 expectRulesetRanges(fixtures.extraSemicolons, [':host {\n margin: 0;;;\n padding: 0;;\n ;display: block;\n}'], [':host']);
179 expectRulesetRanges(fixtures.declarationsWithNoValue, ['div {\n baz;\n}'], ['div']);
180 expectRulesetRanges(fixtures.minifiedRuleset, ['.foo{bar:baz}', 'div .qux{vim:fet;}'], ['.foo', 'div .qux']);
181 expectRulesetRanges(fixtures.psuedoRuleset, ['.foo:bar:not(#rif){baz:qux}'], ['.foo:bar:not(#rif)']);
182 expectRulesetRanges(fixtures.dataUriRuleset, ['.foo{bar:url(qux;gib)}'], ['.foo']);
183 expectRulesetRanges(fixtures.pathologicalComments, ['.foo {\n bar: /*baz*/vim;\n}'], ['.foo']);
184 });
185 it('extracts the correct ranges for rulelists', () => {
186 const expectRulelistRanges = (cssText, expectedRangeStrings) => {
187 const ast = parser.parse(cssText);
188 const nodes = Array.from(getNodesOfType(ast, 'rulelist'));
189 const rangeStrings = nodes.map((n) => {
190 return cssText.substring(n.range.start, n.range.end);
191 });
192 chai_1.expect(rangeStrings).to.be.deep.equal(expectedRangeStrings);
193 };
194 expectRulelistRanges(fixtures.basicRuleset, [`{\n margin: 0;\n padding: 0px\n}`]);
195 expectRulelistRanges(fixtures.atRules, ['{\n font-family: foo;\n}']);
196 expectRulelistRanges(fixtures.keyframes, [
197 '{\n from {\n fiz: 0%;\n }\n\n 99.9% ' +
198 '{\n fiz: 100px;\n buz: true;\n }\n}',
199 '{\n fiz: 0%;\n }',
200 '{\n fiz: 100px;\n buz: true;\n }'
201 ]);
202 expectRulelistRanges(fixtures.customProperties, [
203 '{\n --qux: vim;\n --foo: {\n bar: baz;\n };\n}',
204 '{\n bar: baz;\n }'
205 ]);
206 expectRulelistRanges(fixtures.extraSemicolons, ['{\n margin: 0;;;\n padding: 0;;\n ;display: block;\n}']);
207 expectRulelistRanges(fixtures.declarationsWithNoValue, ['{\n baz;\n}']);
208 expectRulelistRanges(fixtures.minifiedRuleset, ['{bar:baz}', '{vim:fet;}']);
209 expectRulelistRanges(fixtures.psuedoRuleset, ['{baz:qux}']);
210 expectRulelistRanges(fixtures.dataUriRuleset, ['{bar:url(qux;gib)}']);
211 expectRulelistRanges(fixtures.pathologicalComments, ['{\n bar: /*baz*/vim;\n}']);
212 });
213 it('extracts the correct ranges for atRules', () => {
214 const expectAtRuleRanges = (cssText, expectedRangeStrings, expectedNameRangeStrings, expectedParameterRangeStrings) => {
215 const ast = parser.parse(cssText);
216 const nodes = Array.from(getNodesOfType(ast, 'atRule'));
217 const rangeStrings = nodes.map((n) => {
218 return cssText.substring(n.range.start, n.range.end);
219 });
220 const rangeNameStrings = nodes.map((n) => {
221 return cssText.substring(n.nameRange.start, n.nameRange.end);
222 });
223 const rangeParametersStrings = nodes.map((n) => {
224 if (!n.parametersRange) {
225 return '[no parameters]';
226 }
227 return cssText.substring(n.parametersRange.start, n.parametersRange.end);
228 });
229 chai_1.expect(rangeStrings).to.be.deep.equal(expectedRangeStrings);
230 chai_1.expect(rangeNameStrings).to.be.deep.equal(expectedNameRangeStrings);
231 chai_1.expect(rangeParametersStrings)
232 .to.be.deep.equal(expectedParameterRangeStrings);
233 };
234 expectAtRuleRanges(fixtures.basicRuleset, [], [], []);
235 expectAtRuleRanges(fixtures.atRules, [
236 `@import url('foo.css');`,
237 `@font-face {\n font-family: foo;\n}`,
238 `@charset 'foo';`
239 ], ['import', 'font-face', 'charset'], [`url('foo.css')`, `[no parameters]`, `'foo'`]);
240 expectAtRuleRanges(fixtures.keyframes, [
241 '@keyframes foo {\n from {\n fiz: 0%;\n }\n\n 99.9% ' +
242 '{\n fiz: 100px;\n buz: true;\n }\n}',
243 ], ['keyframes'], ['foo']);
244 expectAtRuleRanges(fixtures.customProperties, [], [], []);
245 expectAtRuleRanges(fixtures.extraSemicolons, [], [], []);
246 expectAtRuleRanges(fixtures.declarationsWithNoValue, [], [], []);
247 expectAtRuleRanges(fixtures.minifiedRuleset, [], [], []);
248 expectAtRuleRanges(fixtures.psuedoRuleset, [], [], []);
249 expectAtRuleRanges(fixtures.dataUriRuleset, [], [], []);
250 expectAtRuleRanges(fixtures.pathologicalComments, ['@gak wiz;'], ['gak'], ['wiz']);
251 });
252 });
253});
254function* getNodesOfType(node, type) {
255 for (const n of ast_iterator_1.iterateOverAst(node)) {
256 if (n.type === type) {
257 yield n;
258 }
259 }
260}
261//# sourceMappingURL=parser-test.js.map
\No newline at end of file