mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
Merge remote-tracking branch 'origin/stable'
# Conflicts: # package-lock.json # package.json
This commit is contained in:
commit
926e9e12c0
BIN
db/demo.zip
BIN
db/demo.zip
Binary file not shown.
@ -87,14 +87,16 @@ describe("Lexer expression", () => {
|
|||||||
.toEqual(["#label", "*=*", "text"]);
|
.toEqual(["#label", "*=*", "text"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("simple label operator with in quotes and without", () => {
|
it("simple label operator with in quotes", () => {
|
||||||
expect(lex("#label*=*'text'").expressionTokens)
|
expect(lex("#label*=*'text'").expressionTokens)
|
||||||
.toEqual([
|
.toEqual([
|
||||||
{token: "#label", inQuotes: false, startIndex: 0, endIndex: 5},
|
{token: "#label", inQuotes: false, startIndex: 0, endIndex: 5},
|
||||||
{token: "*=*", inQuotes: false, startIndex: 6, endIndex: 8},
|
{token: "*=*", inQuotes: false, startIndex: 6, endIndex: 8},
|
||||||
{token: "text", inQuotes: true, startIndex: 10, endIndex: 13}
|
{token: "text", inQuotes: true, startIndex: 10, endIndex: 13}
|
||||||
]);
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("simple label operator with param without quotes", () => {
|
||||||
expect(lex("#label*=*text").expressionTokens)
|
expect(lex("#label*=*text").expressionTokens)
|
||||||
.toEqual([
|
.toEqual([
|
||||||
{token: "#label", inQuotes: false, startIndex: 0, endIndex: 5},
|
{token: "#label", inQuotes: false, startIndex: 0, endIndex: 5},
|
||||||
@ -103,6 +105,16 @@ describe("Lexer expression", () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("simple label operator with empty string param", () => {
|
||||||
|
expect(lex("#label = ''").expressionTokens)
|
||||||
|
.toEqual([
|
||||||
|
{token: "#label", inQuotes: false, startIndex: 0, endIndex: 5},
|
||||||
|
{token: "=", inQuotes: false, startIndex: 7, endIndex: 7},
|
||||||
|
// weird case for empty strings which ends up with endIndex < startIndex :-(
|
||||||
|
{token: "", inQuotes: true, startIndex: 10, endIndex: 9}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it("note. prefix also separates fulltext from expression", () => {
|
it("note. prefix also separates fulltext from expression", () => {
|
||||||
expect(lex(`hello fulltext note.labels.capital = Prague`).expressionTokens.map(t => t.token))
|
expect(lex(`hello fulltext note.labels.capital = Prague`).expressionTokens.map(t => t.token))
|
||||||
.toEqual(["note", ".", "labels", ".", "capital", "=", "prague"]);
|
.toEqual(["note", ".", "labels", ".", "capital", "=", "prague"]);
|
||||||
|
@ -19,6 +19,13 @@ function tokens(toks, cur = 0) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function assertIsArchived(exp) {
|
||||||
|
expect(exp.constructor.name).toEqual("PropertyComparisonExp");
|
||||||
|
expect(exp.propertyName).toEqual("isArchived");
|
||||||
|
expect(exp.operator).toEqual("=");
|
||||||
|
expect(exp.comparedValue).toEqual("false");
|
||||||
|
}
|
||||||
|
|
||||||
describe("Parser", () => {
|
describe("Parser", () => {
|
||||||
it("fulltext parser without content", () => {
|
it("fulltext parser without content", () => {
|
||||||
const rootExp = parse({
|
const rootExp = parse({
|
||||||
@ -29,8 +36,9 @@ describe("Parser", () => {
|
|||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("AndExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
expect(rootExp.subExpressions[0].constructor.name).toEqual("PropertyComparisonExp");
|
expect(rootExp.subExpressions[0].constructor.name).toEqual("PropertyComparisonExp");
|
||||||
expect(rootExp.subExpressions[1].constructor.name).toEqual("NoteCacheFlatTextExp");
|
expect(rootExp.subExpressions[1].constructor.name).toEqual("OrExp");
|
||||||
expect(rootExp.subExpressions[1].tokens).toEqual(["hello", "hi"]);
|
expect(rootExp.subExpressions[1].subExpressions[0].constructor.name).toEqual("NoteCacheFlatTextExp");
|
||||||
|
expect(rootExp.subExpressions[1].subExpressions[0].tokens).toEqual(["hello", "hi"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("fulltext parser with content", () => {
|
it("fulltext parser with content", () => {
|
||||||
@ -40,9 +48,12 @@ describe("Parser", () => {
|
|||||||
searchContext: new SearchContext({includeNoteContent: true})
|
searchContext: new SearchContext({includeNoteContent: true})
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("OrExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
|
assertIsArchived(rootExp.subExpressions[0]);
|
||||||
|
|
||||||
const subs = rootExp.subExpressions;
|
expect(rootExp.subExpressions[1].constructor.name).toEqual("OrExp");
|
||||||
|
|
||||||
|
const subs = rootExp.subExpressions[1].subExpressions;
|
||||||
|
|
||||||
expect(subs[0].constructor.name).toEqual("NoteCacheFlatTextExp");
|
expect(subs[0].constructor.name).toEqual("NoteCacheFlatTextExp");
|
||||||
expect(subs[0].tokens).toEqual(["hello", "hi"]);
|
expect(subs[0].tokens).toEqual(["hello", "hi"]);
|
||||||
@ -61,10 +72,12 @@ describe("Parser", () => {
|
|||||||
searchContext: new SearchContext()
|
searchContext: new SearchContext()
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("LabelComparisonExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
expect(rootExp.attributeType).toEqual("label");
|
assertIsArchived(rootExp.subExpressions[0]);
|
||||||
expect(rootExp.attributeName).toEqual("mylabel");
|
expect(rootExp.subExpressions[1].constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(rootExp.comparator).toBeTruthy();
|
expect(rootExp.subExpressions[1].attributeType).toEqual("label");
|
||||||
|
expect(rootExp.subExpressions[1].attributeName).toEqual("mylabel");
|
||||||
|
expect(rootExp.subExpressions[1].comparator).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("simple attribute negation", () => {
|
it("simple attribute negation", () => {
|
||||||
@ -74,10 +87,12 @@ describe("Parser", () => {
|
|||||||
searchContext: new SearchContext()
|
searchContext: new SearchContext()
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("NotExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
expect(rootExp.subExpression.constructor.name).toEqual("AttributeExistsExp");
|
assertIsArchived(rootExp.subExpressions[0]);
|
||||||
expect(rootExp.subExpression.attributeType).toEqual("label");
|
expect(rootExp.subExpressions[1].constructor.name).toEqual("NotExp");
|
||||||
expect(rootExp.subExpression.attributeName).toEqual("mylabel");
|
expect(rootExp.subExpressions[1].subExpression.constructor.name).toEqual("AttributeExistsExp");
|
||||||
|
expect(rootExp.subExpressions[1].subExpression.attributeType).toEqual("label");
|
||||||
|
expect(rootExp.subExpressions[1].subExpression.attributeName).toEqual("mylabel");
|
||||||
|
|
||||||
rootExp = parse({
|
rootExp = parse({
|
||||||
fulltextTokens: [],
|
fulltextTokens: [],
|
||||||
@ -85,10 +100,12 @@ describe("Parser", () => {
|
|||||||
searchContext: new SearchContext()
|
searchContext: new SearchContext()
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("NotExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
expect(rootExp.subExpression.constructor.name).toEqual("AttributeExistsExp");
|
assertIsArchived(rootExp.subExpressions[0]);
|
||||||
expect(rootExp.subExpression.attributeType).toEqual("relation");
|
expect(rootExp.subExpressions[1].constructor.name).toEqual("NotExp");
|
||||||
expect(rootExp.subExpression.attributeName).toEqual("myrelation");
|
expect(rootExp.subExpressions[1].subExpression.constructor.name).toEqual("AttributeExistsExp");
|
||||||
|
expect(rootExp.subExpressions[1].subExpression.attributeType).toEqual("relation");
|
||||||
|
expect(rootExp.subExpressions[1].subExpression.attributeName).toEqual("myrelation");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("simple label AND", () => {
|
it("simple label AND", () => {
|
||||||
@ -99,7 +116,10 @@ describe("Parser", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("AndExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
const [firstSub, secondSub] = rootExp.subExpressions;
|
assertIsArchived(rootExp.subExpressions[0]);
|
||||||
|
|
||||||
|
expect(rootExp.subExpressions[1].constructor.name).toEqual("AndExp");
|
||||||
|
const [firstSub, secondSub] = rootExp.subExpressions[1].subExpressions;
|
||||||
|
|
||||||
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(firstSub.attributeName).toEqual("first");
|
expect(firstSub.attributeName).toEqual("first");
|
||||||
@ -116,7 +136,10 @@ describe("Parser", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("AndExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
const [firstSub, secondSub] = rootExp.subExpressions;
|
assertIsArchived(rootExp.subExpressions[0]);
|
||||||
|
|
||||||
|
expect(rootExp.subExpressions[1].constructor.name).toEqual("AndExp");
|
||||||
|
const [firstSub, secondSub] = rootExp.subExpressions[1].subExpressions;
|
||||||
|
|
||||||
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(firstSub.attributeName).toEqual("first");
|
expect(firstSub.attributeName).toEqual("first");
|
||||||
@ -132,8 +155,11 @@ describe("Parser", () => {
|
|||||||
searchContext: new SearchContext()
|
searchContext: new SearchContext()
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("OrExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
const [firstSub, secondSub] = rootExp.subExpressions;
|
assertIsArchived(rootExp.subExpressions[0]);
|
||||||
|
|
||||||
|
expect(rootExp.subExpressions[1].constructor.name).toEqual("OrExp");
|
||||||
|
const [firstSub, secondSub] = rootExp.subExpressions[1].subExpressions;
|
||||||
|
|
||||||
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(firstSub.attributeName).toEqual("first");
|
expect(firstSub.attributeName).toEqual("first");
|
||||||
@ -155,8 +181,9 @@ describe("Parser", () => {
|
|||||||
expect(firstSub.constructor.name).toEqual("PropertyComparisonExp");
|
expect(firstSub.constructor.name).toEqual("PropertyComparisonExp");
|
||||||
expect(firstSub.propertyName).toEqual('isArchived');
|
expect(firstSub.propertyName).toEqual('isArchived');
|
||||||
|
|
||||||
expect(secondSub.constructor.name).toEqual("NoteCacheFlatTextExp");
|
expect(secondSub.constructor.name).toEqual("OrExp");
|
||||||
expect(secondSub.tokens).toEqual(["hello"]);
|
expect(secondSub.subExpressions[0].constructor.name).toEqual("NoteCacheFlatTextExp");
|
||||||
|
expect(secondSub.subExpressions[0].tokens).toEqual(["hello"]);
|
||||||
|
|
||||||
expect(thirdSub.constructor.name).toEqual("LabelComparisonExp");
|
expect(thirdSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(thirdSub.attributeName).toEqual("mylabel");
|
expect(thirdSub.attributeName).toEqual("mylabel");
|
||||||
@ -169,8 +196,11 @@ describe("Parser", () => {
|
|||||||
searchContext: new SearchContext()
|
searchContext: new SearchContext()
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("OrExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
const [firstSub, secondSub] = rootExp.subExpressions;
|
assertIsArchived(rootExp.subExpressions[0]);
|
||||||
|
|
||||||
|
expect(rootExp.subExpressions[1].constructor.name).toEqual("OrExp");
|
||||||
|
const [firstSub, secondSub] = rootExp.subExpressions[1].subExpressions;
|
||||||
|
|
||||||
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
expect(firstSub.constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(firstSub.attributeName).toEqual("first");
|
expect(firstSub.attributeName).toEqual("first");
|
||||||
@ -232,10 +262,12 @@ describe("Invalid expressions", () => {
|
|||||||
searchContext: new SearchContext()
|
searchContext: new SearchContext()
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(rootExp.constructor.name).toEqual("LabelComparisonExp");
|
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||||
expect(rootExp.attributeType).toEqual("label");
|
assertIsArchived(rootExp.subExpressions[0]);
|
||||||
expect(rootExp.attributeName).toEqual("first");
|
expect(rootExp.subExpressions[1].constructor.name).toEqual("LabelComparisonExp");
|
||||||
expect(rootExp.comparator).toBeTruthy();
|
expect(rootExp.subExpressions[1].attributeType).toEqual("label");
|
||||||
|
expect(rootExp.subExpressions[1].attributeName).toEqual("first");
|
||||||
|
expect(rootExp.subExpressions[1].comparator).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("searching by relation without note property", () => {
|
it("searching by relation without note property", () => {
|
||||||
|
@ -562,8 +562,8 @@ describe("Search", () => {
|
|||||||
expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Austria");
|
expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Austria");
|
||||||
expect(noteCache.notes[searchResults[1].noteId].title).toEqual("Italy");
|
expect(noteCache.notes[searchResults[1].noteId].title).toEqual("Italy");
|
||||||
|
|
||||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 0', searchContext);
|
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 1', searchContext);
|
||||||
expect(searchResults.length).toEqual(0);
|
expect(searchResults.length).toEqual(1);
|
||||||
|
|
||||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 1000', searchContext);
|
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 1000', searchContext);
|
||||||
expect(searchResults.length).toEqual(4);
|
expect(searchResults.length).toEqual(4);
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
const {note} = require('./note_cache_mocking.js');
|
const {note} = require('./note_cache_mocking.js');
|
||||||
const ValueExtractor = require('../../src/services/search/value_extractor.js');
|
const ValueExtractor = require('../../src/services/search/value_extractor.js');
|
||||||
const noteCache = require('../../src/services/note_cache/note_cache.js');
|
const noteCache = require('../../src/services/note_cache/note_cache.js');
|
||||||
|
const SearchContext = require("../../src/services/search/search_context.js");
|
||||||
|
|
||||||
|
const dsc = new SearchContext();
|
||||||
|
|
||||||
describe("Value extractor", () => {
|
describe("Value extractor", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -10,7 +13,7 @@ describe("Value extractor", () => {
|
|||||||
it("simple title extraction", async () => {
|
it("simple title extraction", async () => {
|
||||||
const europe = note("Europe").note;
|
const europe = note("Europe").note;
|
||||||
|
|
||||||
const valueExtractor = new ValueExtractor(["note", "title"]);
|
const valueExtractor = new ValueExtractor(dsc, ["note", "title"]);
|
||||||
|
|
||||||
expect(valueExtractor.validate()).toBeFalsy();
|
expect(valueExtractor.validate()).toBeFalsy();
|
||||||
expect(valueExtractor.extract(europe)).toEqual("Europe");
|
expect(valueExtractor.extract(europe)).toEqual("Europe");
|
||||||
@ -21,12 +24,12 @@ describe("Value extractor", () => {
|
|||||||
.label("Capital", "Vienna")
|
.label("Capital", "Vienna")
|
||||||
.note;
|
.note;
|
||||||
|
|
||||||
let valueExtractor = new ValueExtractor(["note", "labels", "capital"]);
|
let valueExtractor = new ValueExtractor(dsc, ["note", "labels", "capital"]);
|
||||||
|
|
||||||
expect(valueExtractor.validate()).toBeFalsy();
|
expect(valueExtractor.validate()).toBeFalsy();
|
||||||
expect(valueExtractor.extract(austria)).toEqual("Vienna");
|
expect(valueExtractor.extract(austria)).toEqual("Vienna");
|
||||||
|
|
||||||
valueExtractor = new ValueExtractor(["#capital"]);
|
valueExtractor = new ValueExtractor(dsc, ["#capital"]);
|
||||||
|
|
||||||
expect(valueExtractor.validate()).toBeFalsy();
|
expect(valueExtractor.validate()).toBeFalsy();
|
||||||
expect(valueExtractor.extract(austria)).toEqual("Vienna");
|
expect(valueExtractor.extract(austria)).toEqual("Vienna");
|
||||||
@ -38,12 +41,12 @@ describe("Value extractor", () => {
|
|||||||
.child(note("Austria")
|
.child(note("Austria")
|
||||||
.child(vienna));
|
.child(vienna));
|
||||||
|
|
||||||
let valueExtractor = new ValueExtractor(["note", "children", "children", "title"]);
|
let valueExtractor = new ValueExtractor(dsc, ["note", "children", "children", "title"]);
|
||||||
|
|
||||||
expect(valueExtractor.validate()).toBeFalsy();
|
expect(valueExtractor.validate()).toBeFalsy();
|
||||||
expect(valueExtractor.extract(europe.note)).toEqual("Vienna");
|
expect(valueExtractor.extract(europe.note)).toEqual("Vienna");
|
||||||
|
|
||||||
valueExtractor = new ValueExtractor(["note", "parents", "parents", "title"]);
|
valueExtractor = new ValueExtractor(dsc, ["note", "parents", "parents", "title"]);
|
||||||
|
|
||||||
expect(valueExtractor.validate()).toBeFalsy();
|
expect(valueExtractor.validate()).toBeFalsy();
|
||||||
expect(valueExtractor.extract(vienna.note)).toEqual("Europe");
|
expect(valueExtractor.extract(vienna.note)).toEqual("Europe");
|
||||||
@ -56,12 +59,12 @@ describe("Value extractor", () => {
|
|||||||
.relation('neighbor', czechRepublic.note)
|
.relation('neighbor', czechRepublic.note)
|
||||||
.relation('neighbor', slovakia.note);
|
.relation('neighbor', slovakia.note);
|
||||||
|
|
||||||
let valueExtractor = new ValueExtractor(["note", "relations", "neighbor", "labels", "capital"]);
|
let valueExtractor = new ValueExtractor(dsc, ["note", "relations", "neighbor", "labels", "capital"]);
|
||||||
|
|
||||||
expect(valueExtractor.validate()).toBeFalsy();
|
expect(valueExtractor.validate()).toBeFalsy();
|
||||||
expect(valueExtractor.extract(austria.note)).toEqual("Prague");
|
expect(valueExtractor.extract(austria.note)).toEqual("Prague");
|
||||||
|
|
||||||
valueExtractor = new ValueExtractor(["~neighbor", "labels", "capital"]);
|
valueExtractor = new ValueExtractor(dsc, ["~neighbor", "labels", "capital"]);
|
||||||
|
|
||||||
expect(valueExtractor.validate()).toBeFalsy();
|
expect(valueExtractor.validate()).toBeFalsy();
|
||||||
expect(valueExtractor.extract(austria.note)).toEqual("Prague");
|
expect(valueExtractor.extract(austria.note)).toEqual("Prague");
|
||||||
@ -70,17 +73,17 @@ describe("Value extractor", () => {
|
|||||||
|
|
||||||
describe("Invalid value extractor property path", () => {
|
describe("Invalid value extractor property path", () => {
|
||||||
it('each path must start with "note" (or label/relation)',
|
it('each path must start with "note" (or label/relation)',
|
||||||
() => expect(new ValueExtractor(["neighbor"]).validate()).toBeTruthy());
|
() => expect(new ValueExtractor(dsc, ["neighbor"]).validate()).toBeTruthy());
|
||||||
|
|
||||||
it("extra path element after terminal label",
|
it("extra path element after terminal label",
|
||||||
() => expect(new ValueExtractor(["~neighbor", "labels", "capital", "noteId"]).validate()).toBeTruthy());
|
() => expect(new ValueExtractor(dsc, ["~neighbor", "labels", "capital", "noteId"]).validate()).toBeTruthy());
|
||||||
|
|
||||||
it("extra path element after terminal title",
|
it("extra path element after terminal title",
|
||||||
() => expect(new ValueExtractor(["note", "title", "isProtected"]).validate()).toBeTruthy());
|
() => expect(new ValueExtractor(dsc, ["note", "title", "isProtected"]).validate()).toBeTruthy());
|
||||||
|
|
||||||
it("relation name and note property is missing",
|
it("relation name and note property is missing",
|
||||||
() => expect(new ValueExtractor(["note", "relations"]).validate()).toBeTruthy());
|
() => expect(new ValueExtractor(dsc, ["note", "relations"]).validate()).toBeTruthy());
|
||||||
|
|
||||||
it("relation is specified but target note property is not specified",
|
it("relation is specified but target note property is not specified",
|
||||||
() => expect(new ValueExtractor(["note", "relations", "myrel"]).validate()).toBeTruthy());
|
() => expect(new ValueExtractor(dsc, ["note", "relations", "myrel"]).validate()).toBeTruthy());
|
||||||
});
|
});
|
||||||
|
@ -21,8 +21,8 @@ function lex(str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishWord(endIndex) {
|
function finishWord(endIndex, createAlsoForEmptyWords = false) {
|
||||||
if (currentWord === '') {
|
if (currentWord === '' && !createAlsoForEmptyWords) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ function lex(str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (quotes === chr) {
|
else if (quotes === chr) {
|
||||||
finishWord(i - 1);
|
finishWord(i - 1, true);
|
||||||
|
|
||||||
quotes = false;
|
quotes = false;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user