From c7f6e474b19ee4e21d839ada2473836bd6b943c1 Mon Sep 17 00:00:00 2001 From: Romain Menke Date: Sat, 11 May 2024 23:52:52 +0200 Subject: [PATCH 1/2] add source index to selector nodes --- src/__tests__/node.mjs | 2 +- src/__tests__/sourceIndex.mjs | 54 +++++++++++++++++++++++++++++++++++ src/parser.js | 17 +++++++++-- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/__tests__/node.mjs b/src/__tests__/node.mjs index f248bd5..859bc2f 100644 --- a/src/__tests__/node.mjs +++ b/src/__tests__/node.mjs @@ -99,8 +99,8 @@ test('Node#isAtPosition', (t) => { let notSelector = pseudoNot.first; t.deepEqual(notSelector.isAtPosition(1, 1), false); t.deepEqual(notSelector.isAtPosition(1, 4), false); - t.deepEqual(notSelector.isAtPosition(1, 5), true); t.deepEqual(notSelector.isAtPosition(1, 6), true); + t.deepEqual(notSelector.isAtPosition(1, 7), true); t.deepEqual(notSelector.isAtPosition(1, 9), true); t.deepEqual(notSelector.isAtPosition(1, 10), true); t.deepEqual(notSelector.isAtPosition(1, 11), false); diff --git a/src/__tests__/sourceIndex.mjs b/src/__tests__/sourceIndex.mjs index f99003d..34d9cf2 100644 --- a/src/__tests__/sourceIndex.mjs +++ b/src/__tests__/sourceIndex.mjs @@ -1,12 +1,18 @@ import {test} from './util/helpers.mjs'; test('universal selector', '*', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 1); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[0].source.start.column, 1); t.deepEqual(tree.nodes[0].nodes[0].source.end.column, 1); t.deepEqual(tree.nodes[0].nodes[0].sourceIndex, 0); }); test('lobotomized owl selector', ' * + * ', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 6); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[0].source.start.column, 2); t.deepEqual(tree.nodes[0].nodes[0].source.end.column, 2); t.deepEqual(tree.nodes[0].nodes[0].sourceIndex, 1); @@ -19,12 +25,18 @@ test('lobotomized owl selector', ' * + * ', (t, tree) => { }); test('comment', '/**\n * Hello!\n */', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 3); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[0].source.start.column, 1); t.deepEqual(tree.nodes[0].nodes[0].source.end.column, 3); t.deepEqual(tree.nodes[0].nodes[0].sourceIndex, 0); }); test('comment & universal selectors', '*/*test*/*', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 10); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[0].source.start.column, 1); t.deepEqual(tree.nodes[0].nodes[0].source.end.column, 1); t.deepEqual(tree.nodes[0].nodes[0].sourceIndex, 0); @@ -37,27 +49,42 @@ test('comment & universal selectors', '*/*test*/*', (t, tree) => { }); test('tag selector', 'h1', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 2); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[0].source.start.column, 1); t.deepEqual(tree.nodes[0].nodes[0].source.end.column, 2); t.deepEqual(tree.nodes[0].nodes[0].sourceIndex, 0); }); test('id selector', '#id', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 3); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[0].source.start.column, 1); t.deepEqual(tree.nodes[0].nodes[0].source.end.column, 3); t.deepEqual(tree.nodes[0].nodes[0].sourceIndex, 0); }); test('tag selector followed by id selector', 'h1, #id', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 2); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[0].source.start.column, 1); t.deepEqual(tree.nodes[0].nodes[0].source.end.column, 2); t.deepEqual(tree.nodes[0].nodes[0].sourceIndex, 0); + t.deepEqual(tree.nodes[1].source.start.column, 4); + t.deepEqual(tree.nodes[1].source.end.column, 7); + t.deepEqual(tree.nodes[1].sourceIndex, 3); t.deepEqual(tree.nodes[1].nodes[0].source.start.column, 5); t.deepEqual(tree.nodes[1].nodes[0].source.end.column, 7); t.deepEqual(tree.nodes[1].nodes[0].sourceIndex, 4); }); test('multiple id selectors', '#one#two', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 8); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[0].source.start.column, 1); t.deepEqual(tree.nodes[0].nodes[0].source.end.column, 4); t.deepEqual(tree.nodes[0].nodes[0].sourceIndex, 0); @@ -67,6 +94,9 @@ test('multiple id selectors', '#one#two', (t, tree) => { }); test('multiple id selectors (2)', '#one#two#three#four', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 19); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[2].source.start.column, 9); t.deepEqual(tree.nodes[0].nodes[2].source.end.column, 14); t.deepEqual(tree.nodes[0].nodes[2].sourceIndex, 8); @@ -76,24 +106,39 @@ test('multiple id selectors (2)', '#one#two#three#four', (t, tree) => { }); test('multiple id selectors (3)', '#one#two,#three#four', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 8); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[1].source.start.column, 5); t.deepEqual(tree.nodes[0].nodes[1].source.end.column, 8); t.deepEqual(tree.nodes[0].nodes[1].sourceIndex, 4); + t.deepEqual(tree.nodes[1].source.start.column, 10); + t.deepEqual(tree.nodes[1].source.end.column, 20); + t.deepEqual(tree.nodes[1].sourceIndex, 9); t.deepEqual(tree.nodes[1].nodes[1].source.start.column, 16); t.deepEqual(tree.nodes[1].nodes[1].source.end.column, 20); t.deepEqual(tree.nodes[1].nodes[1].sourceIndex, 15); }); test('multiple class selectors', '.one.two,.three.four', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 8); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[1].source.start.column, 5); t.deepEqual(tree.nodes[0].nodes[1].source.end.column, 8); t.deepEqual(tree.nodes[0].nodes[1].sourceIndex, 4); + t.deepEqual(tree.nodes[1].source.start.column, 10); + t.deepEqual(tree.nodes[1].source.end.column, 20); + t.deepEqual(tree.nodes[1].sourceIndex, 9); t.deepEqual(tree.nodes[1].nodes[1].source.start.column, 16); t.deepEqual(tree.nodes[1].nodes[1].source.end.column, 20); t.deepEqual(tree.nodes[1].nodes[1].sourceIndex, 15); }); test('attribute selector', '[name="james"]', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 14); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[0].source.start.line, 1); t.deepEqual(tree.nodes[0].nodes[0].source.start.column, 1); t.deepEqual(tree.nodes[0].nodes[0].source.end.column, 14); @@ -131,10 +176,19 @@ test('pseudo-class', 'h1:first-child', (t, tree) => { }); test('pseudo-class with argument', 'h1:not(.strudel, .food)', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 23); + t.deepEqual(tree.nodes[0].sourceIndex, 0); t.deepEqual(tree.nodes[0].nodes[1].source.start.line, 1); t.deepEqual(tree.nodes[0].nodes[1].source.start.column, 3); t.deepEqual(tree.nodes[0].nodes[1].source.end.column, 23); t.deepEqual(tree.nodes[0].nodes[1].sourceIndex, 2); + t.deepEqual(tree.nodes[0].nodes[1].nodes[0].source.start.column, 8); + t.deepEqual(tree.nodes[0].nodes[1].nodes[0].source.end.column, 15); + t.deepEqual(tree.nodes[0].nodes[1].nodes[0].sourceIndex, 7); + t.deepEqual(tree.nodes[0].nodes[1].nodes[1].source.start.column, 17); + t.deepEqual(tree.nodes[0].nodes[1].nodes[1].source.end.column, 23); + t.deepEqual(tree.nodes[0].nodes[1].nodes[1].sourceIndex, 16); }); test('pseudo-element', 'h1::before', (t, tree) => { diff --git a/src/parser.js b/src/parser.js index 577b89c..4815c6e 100644 --- a/src/parser.js +++ b/src/parser.js @@ -131,7 +131,10 @@ export default class Parser { this.root.errorGenerator = this._errorGenerator(); - const selector = new Selector({source: {start: {line: 1, column: 1}}}); + const selector = new Selector({ + source: {start: {line: 1, column: 1}}, + sourceIndex: 0, + }); this.root.append(selector); this.current = selector; @@ -608,7 +611,12 @@ export default class Parser { return; } this.current._inferEndPosition(); - const selector = new Selector({source: {start: tokenStart(this.tokens[this.position + 1])}}); + const selector = new Selector({ + source: { + start: tokenStart(this.tokens[this.position + 1]), + }, + sourceIndex: this.tokens[this.position + 1][TOKEN.START_POS], + }); this.current.parent.append(selector); this.current = selector; this.position ++; @@ -685,7 +693,10 @@ export default class Parser { let unbalanced = 1; this.position ++; if (last && last.type === types.PSEUDO) { - const selector = new Selector({source: {start: tokenStart(this.tokens[this.position - 1])}}); + const selector = new Selector({ + source: {start: tokenStart(this.tokens[this.position])}, + sourceIndex: this.tokens[this.position][TOKEN.START_POS], + }); const cache = this.current; last.append(selector); this.current = selector; From ea057eff02ee4fe0658f173c9c680c7f29eb7ccf Mon Sep 17 00:00:00 2001 From: Romain Menke Date: Sun, 12 May 2024 13:36:17 +0200 Subject: [PATCH 2/2] add a test for a pseudo without arguments --- src/__tests__/sourceIndex.mjs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/__tests__/sourceIndex.mjs b/src/__tests__/sourceIndex.mjs index 34d9cf2..258cfca 100644 --- a/src/__tests__/sourceIndex.mjs +++ b/src/__tests__/sourceIndex.mjs @@ -175,6 +175,19 @@ test('pseudo-class', 'h1:first-child', (t, tree) => { t.deepEqual(tree.nodes[0].nodes[1].sourceIndex, 2); }); +test('pseudo-class without argument', ':not()', (t, tree) => { + t.deepEqual(tree.nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].source.end.column, 6); + t.deepEqual(tree.nodes[0].sourceIndex, 0); + t.deepEqual(tree.nodes[0].nodes[0].source.start.line, 1); + t.deepEqual(tree.nodes[0].nodes[0].source.start.column, 1); + t.deepEqual(tree.nodes[0].nodes[0].source.end.column, 6); + t.deepEqual(tree.nodes[0].nodes[0].sourceIndex, 0); + t.deepEqual(tree.nodes[0].nodes[0].nodes[0].source.start.column, 6); + t.deepEqual(tree.nodes[0].nodes[0].nodes[0].source.end.column, 6); + t.deepEqual(tree.nodes[0].nodes[0].nodes[0].sourceIndex, 5); +}); + test('pseudo-class with argument', 'h1:not(.strudel, .food)', (t, tree) => { t.deepEqual(tree.nodes[0].source.start.column, 1); t.deepEqual(tree.nodes[0].source.end.column, 23);