mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 13:00:36 -05:00
fix: sibling selectors
This commit is contained in:
parent
8d9f9ce5e2
commit
321a1fe57e
5 changed files with 203 additions and 53 deletions
|
@ -217,6 +217,63 @@ function readValue(ctx, offset, search) {
|
|||
throw new Error(`Unknown prop kind: ${kind}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AstContext["buf"]} buf
|
||||
* @param {number} child
|
||||
* @returns {null | [number, number]}
|
||||
*/
|
||||
function findChildOffset(buf, child) {
|
||||
let offset = readU32(buf, child + 1);
|
||||
|
||||
// type + parentId + SpanLo + SpanHi
|
||||
offset += 1 + 4 + 4 + 4;
|
||||
|
||||
const propCount = buf[offset++];
|
||||
for (let i = 0; i < propCount; i++) {
|
||||
const _prop = buf[offset++];
|
||||
const kind = buf[offset++];
|
||||
|
||||
switch (kind) {
|
||||
case PropFlags.Ref: {
|
||||
const start = offset;
|
||||
const value = readU32(buf, offset);
|
||||
offset += 4;
|
||||
if (value === child) {
|
||||
return [start, -1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PropFlags.RefArr: {
|
||||
const start = offset;
|
||||
|
||||
const len = readU32(buf, offset);
|
||||
offset += 4;
|
||||
|
||||
for (let j = 0; j < len; j++) {
|
||||
const value = readU32(buf, offset);
|
||||
offset += 4;
|
||||
if (value === child) {
|
||||
return [start, j];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PropFlags.String:
|
||||
offset += 4;
|
||||
break;
|
||||
case PropFlags.Bool:
|
||||
offset++;
|
||||
break;
|
||||
case PropFlags.Null:
|
||||
case PropFlags.Undefined:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AstContext} ctx
|
||||
* @param {number} offset
|
||||
|
@ -386,9 +443,8 @@ class MatchCtx {
|
|||
const { buf } = this;
|
||||
|
||||
offset = findPropOffset(buf, offset, propIds[idx]);
|
||||
// console.log("attr value", offset, propIds, idx);
|
||||
if (offset === -1) return undefined;
|
||||
const prop = buf[offset++];
|
||||
const _prop = buf[offset++];
|
||||
const kind = buf[offset++];
|
||||
|
||||
if (kind === PropFlags.Ref) {
|
||||
|
@ -398,7 +454,7 @@ class MatchCtx {
|
|||
return this.getAttrPathValue(value, propIds, idx + 1);
|
||||
} else if (kind === PropFlags.RefArr) {
|
||||
// FIXME
|
||||
const count = readU32(buf, offset);
|
||||
const _count = readU32(buf, offset);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
|
@ -452,22 +508,133 @@ class MatchCtx {
|
|||
return true;
|
||||
}
|
||||
|
||||
getFirstChild() {
|
||||
// FIXME
|
||||
return 0;
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @returns {number}
|
||||
*/
|
||||
getFirstChild(offset) {
|
||||
const { buf } = this;
|
||||
|
||||
// type + parentId + SpanLo + SpanHi
|
||||
offset += 1 + 4 + 4 + 4;
|
||||
|
||||
const count = buf[offset++];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const _prop = buf[offset++];
|
||||
const kind = buf[offset++];
|
||||
|
||||
switch (kind) {
|
||||
case PropFlags.Ref: {
|
||||
const v = readU32(buf, offset);
|
||||
offset += 4;
|
||||
return v;
|
||||
}
|
||||
case PropFlags.RefArr: {
|
||||
const len = readU32(buf, offset);
|
||||
offset += 4;
|
||||
for (let j = 0; j < len; j++) {
|
||||
const v = readU32(buf, offset);
|
||||
offset += 4;
|
||||
return v;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
case PropFlags.String:
|
||||
offset += 4;
|
||||
break;
|
||||
case PropFlags.Bool:
|
||||
offset++;
|
||||
break;
|
||||
case PropFlags.Null:
|
||||
case PropFlags.Undefined:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
getLastChild() {
|
||||
// FIXME
|
||||
return 0;
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @returns {number}
|
||||
*/
|
||||
getLastChild(offset) {
|
||||
const { buf } = this;
|
||||
|
||||
// type + parentId + SpanLo + SpanHi
|
||||
offset += 1 + 4 + 4 + 4;
|
||||
|
||||
let last = -1;
|
||||
|
||||
const count = buf[offset++];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const _prop = buf[offset++];
|
||||
const kind = buf[offset++];
|
||||
|
||||
switch (kind) {
|
||||
case PropFlags.Ref: {
|
||||
const v = readU32(buf, offset);
|
||||
offset += 4;
|
||||
last = v;
|
||||
break;
|
||||
}
|
||||
case PropFlags.RefArr: {
|
||||
const len = readU32(buf, offset);
|
||||
offset += 4;
|
||||
for (let j = 0; j < len; j++) {
|
||||
const v = readU32(buf, offset);
|
||||
last = v;
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PropFlags.String:
|
||||
offset += 4;
|
||||
break;
|
||||
case PropFlags.Bool:
|
||||
offset++;
|
||||
break;
|
||||
case PropFlags.Null:
|
||||
case PropFlags.Undefined:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
getSiblingBefore() {
|
||||
// FIXME
|
||||
return 0;
|
||||
}
|
||||
getSiblings() {
|
||||
// FIXME
|
||||
return [];
|
||||
|
||||
/**
|
||||
* @param {number} id
|
||||
* @returns {number[]}
|
||||
*/
|
||||
getSiblings(id) {
|
||||
const { buf } = this;
|
||||
|
||||
const result = findChildOffset(buf, id);
|
||||
// Happens for program nodes
|
||||
if (result === null) return [];
|
||||
|
||||
if (result[1] === -1) {
|
||||
return [id];
|
||||
}
|
||||
|
||||
let offset = result[0];
|
||||
const count = readU32(buf, offset);
|
||||
offset += 4;
|
||||
|
||||
/** @type {number[]} */
|
||||
const out = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const v = readU32(buf, offset);
|
||||
offset += 4;
|
||||
out.push(v);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -623,8 +790,6 @@ export function runPluginsForFile(fileName, serializedAst) {
|
|||
try {
|
||||
fn(node);
|
||||
} catch (err) {
|
||||
// FIXME: console here doesn't support error cause
|
||||
console.log(err);
|
||||
throw new Error(`Visitor "${name}" of plugin "${id}" errored`, {
|
||||
cause: err,
|
||||
});
|
||||
|
@ -734,7 +899,6 @@ function traverse(ctx, visitors, offset) {
|
|||
|
||||
const propCount = buf[offset];
|
||||
offset += 1;
|
||||
// console.log({ propCount });
|
||||
|
||||
for (let i = 0; i < propCount; i++) {
|
||||
const kind = buf[offset + 1];
|
||||
|
|
|
@ -900,12 +900,12 @@ function matchChild(next) {
|
|||
*/
|
||||
function matchAdjacent(next) {
|
||||
return (ctx, id) => {
|
||||
const parent = ctx.getParent(id);
|
||||
if (parent < 0) return false;
|
||||
const siblings = ctx.getSiblings(id);
|
||||
const idx = siblings.indexOf(id) - 1;
|
||||
|
||||
const prev = ctx.getSiblingBefore(parent, id);
|
||||
if (prev < 0) return false;
|
||||
if (idx < 0) return false;
|
||||
|
||||
const prev = siblings[idx];
|
||||
return next(ctx, prev);
|
||||
};
|
||||
}
|
||||
|
@ -916,16 +916,14 @@ function matchAdjacent(next) {
|
|||
*/
|
||||
function matchFollowing(next) {
|
||||
return (ctx, id) => {
|
||||
const parent = ctx.getParent(id);
|
||||
if (parent < 0) return false;
|
||||
const siblings = ctx.getSiblings(id);
|
||||
const idx = siblings.indexOf(id) - 1;
|
||||
|
||||
let prev = ctx.getSiblingBefore(parent, id);
|
||||
while (prev > -1) {
|
||||
if (next(ctx, prev)) {
|
||||
return true;
|
||||
}
|
||||
if (idx < 0) return false;
|
||||
|
||||
prev = ctx.getSiblingBefore(parent, prev);
|
||||
for (let i = idx; i >= 0; i--) {
|
||||
const sib = siblings[i];
|
||||
if (next(ctx, sib)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -116,6 +116,14 @@ Deno.test("Lexer - Relation ~", () => {
|
|||
{ token: Token.Op, value: "~" },
|
||||
{ token: Token.Word, value: "Bar" },
|
||||
]);
|
||||
|
||||
expect(testLexer("Foo Bar ~ Bar")).toEqual([
|
||||
{ token: Token.Word, value: "Foo" },
|
||||
{ token: Token.Space, value: "" },
|
||||
{ token: Token.Word, value: "Bar" },
|
||||
{ token: Token.Op, value: "~" },
|
||||
{ token: Token.Word, value: "Bar" },
|
||||
]);
|
||||
});
|
||||
|
||||
Deno.test("Lexer - Attr", () => {
|
||||
|
|
|
@ -147,6 +147,7 @@ class FakeContext implements MatchCtx {
|
|||
} else if (
|
||||
first === -1 && prop.value !== null && typeof prop.value === "object"
|
||||
) {
|
||||
// @ts-ignore loosely typed
|
||||
first = prop.value;
|
||||
}
|
||||
}
|
||||
|
@ -164,6 +165,7 @@ class FakeContext implements MatchCtx {
|
|||
if (prop.value.length === 0) return -1;
|
||||
return prop.value.at(-1);
|
||||
} else if (prop.value !== null && typeof prop.value !== "object") {
|
||||
// @ts-ignore loosely typed
|
||||
last = prop.value;
|
||||
}
|
||||
}
|
||||
|
@ -176,27 +178,6 @@ class FakeContext implements MatchCtx {
|
|||
return node.parentId;
|
||||
}
|
||||
|
||||
getSiblingBefore(parentId: number, sib: number): number {
|
||||
const node = this.ids.get(parentId);
|
||||
if (node === undefined) return -1;
|
||||
|
||||
let prev = -1;
|
||||
for (const prop of node.props) {
|
||||
if (prop.value === sib) return prev;
|
||||
|
||||
if (Array.isArray(prop.value)) {
|
||||
for (const id of prop.value) {
|
||||
if (id === sib) return prev;
|
||||
prev = id;
|
||||
}
|
||||
} else {
|
||||
prev = prop.value;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
getSiblings(id: number): number[] {
|
||||
const parent = this.getParent(id);
|
||||
const node = this.ids.get(parent);
|
||||
|
|
1
cli/js/40_lint_types.d.ts
vendored
1
cli/js/40_lint_types.d.ts
vendored
|
@ -102,7 +102,6 @@ export interface ILexer {
|
|||
export interface MatchContext {
|
||||
getFirstChild(id: number): number;
|
||||
getLastChild(id: number): number;
|
||||
getSiblingBefore(parentId: number, sib: number): number;
|
||||
getSiblings(id: number): number[];
|
||||
getParent(id: number): number;
|
||||
getType(id: number): number;
|
||||
|
|
Loading…
Add table
Reference in a new issue