1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-10 05:30:01 +00:00

Add has field filter operator

This commit is contained in:
Matt Gibson
2025-03-20 09:25:05 -07:00
parent b8ba35f576
commit c05558c476
4 changed files with 37 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ export const AstNodeTypeNames = [
"or",
"term",
"fieldTerm",
"hasField",
"hasAttachment",
"hasUri",
"hasFolder",
@@ -30,6 +31,7 @@ export type AstNode =
| Or
| Term
| FieldTerm
| HasField
| HasAttachment
| HasUri
| HasFolder
@@ -118,6 +120,14 @@ export function isFieldTerm(x: AstNode): x is FieldTerm {
return x.type === "fieldTerm";
}
export type HasField = AstNodeBase & {
type: "hasField";
field: string;
};
export function isHasField(x: AstNode): x is HasField {
return x.type === "hasField";
}
export type HasAttachment = AstNodeBase & {
type: "hasAttachment";
};

View File

@@ -47,6 +47,8 @@ TERM ->
%string {% function(d) { const start = d[0].offset; const end = d[0].offset + d[0].value.length; return { type: 'term', value: d[0].value, start, end, length: d[0].value.length } } %}
# specified field search term
| %func_field %string %access %string {% function(d) { const start = d[0].offset; const end = d[3].offset + d[3].value.length; return { type: 'fieldTerm', field: d[1].value, term: d[3].value, start, end, length: end - start + 1 } } %}
# Has specified field as non-null
| %func_has %func_field %string {% function(d) { const start = d[0].offset; const end = d[2].offset + d[2].value.length; return { type: 'hasField', field: d[2].value, start, end, length: end - start + 1 } } %}
# only items with attachments
| %func_has "attachment" {% function(d) { const start = d[0].offset; const length = 14; return { type: 'hasAttachment', start, end: d[0].offset + length, length } } %}
# only items with URIs

View File

@@ -185,6 +185,19 @@ const grammar: Grammar = {
};
},
},
{
name: "TERM",
symbols: [
lexer.has("func_has") ? { type: "func_has" } : func_has,
lexer.has("func_field") ? { type: "func_field" } : func_field,
lexer.has("string") ? { type: "string" } : string,
],
postprocess: function (d) {
const start = d[0].offset;
const end = d[2].offset + d[2].value.length;
return { type: "hasField", field: d[2].value, start, end, length: end - start + 1 };
},
},
{
name: "TERM",
symbols: [lexer.has("func_has") ? { type: "func_has" } : func_has, { literal: "attachment" }],

View File

@@ -14,6 +14,7 @@ import {
isAnd,
isFieldTerm,
isHasAttachment,
isHasField,
isHasFolder,
isHasUri,
isInCollection,
@@ -118,6 +119,17 @@ function handleNode(node: AstNode): { filter: (context: SearchContext) => Search
};
},
};
} else if (isHasField(node)) {
const fieldTest = fieldNameToRegexTest(node.field);
return {
filter: (context) => ({
...context,
ciphers: context.ciphers.filter((cipher) => {
const foundValues = fieldValues(cipher, fieldTest);
return foundValues.fields.some((foundValue) => !!foundValue.value);
}),
}),
};
} else if (isHasAttachment(node)) {
return {
filter: (context) => ({