mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 09:58:32 +02:00
attribute parser and tests WIP
This commit is contained in:
parent
01a7af965c
commit
ed9fbae65d
@ -19,7 +19,8 @@
|
|||||||
"build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/collapsible_widget.js",
|
"build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/collapsible_widget.js",
|
||||||
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs",
|
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs",
|
||||||
"webpack": "npx webpack -c webpack-desktop.config.js && npx webpack -c webpack-mobile.config.js && npx webpack -c webpack-setup.config.js",
|
"webpack": "npx webpack -c webpack-desktop.config.js && npx webpack -c webpack-mobile.config.js && npx webpack -c webpack-setup.config.js",
|
||||||
"test": "jasmine"
|
"test": "jasmine",
|
||||||
|
"test-es6": "node -r esm spec-es6/attribute_parser.spec.js "
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async-mutex": "0.2.2",
|
"async-mutex": "0.2.2",
|
||||||
|
@ -1,10 +1,62 @@
|
|||||||
import attributeParser from '../src/public/app/services/attribute_parser.js';
|
import attributeParser from '../src/public/app/services/attribute_parser.js';
|
||||||
import {describe, it, expect, execute} from './mini_test.js';
|
import {describe, it, expect, execute} from './mini_test.js';
|
||||||
|
|
||||||
describe("Lexer fulltext", () => {
|
describe("Lexer", () => {
|
||||||
it("simple label", () => {
|
it("simple label", () => {
|
||||||
expect(attributeParser.lexer("#label")).toEqual(["#label"]);
|
expect(attributeParser.lexer("#label")).toEqual(["#label"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("label with value", () => {
|
||||||
|
expect(attributeParser.lexer("#label=Hallo")).toEqual(["#label", "=", "Hallo"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("relation with value", () => {
|
||||||
|
expect(attributeParser.lexer('~relation=<a class="reference-link" href="#root/RclIpMauTOKS/NFi2gL4xtPxM" data-note-path="root/RclIpMauTOKS/NFi2gL4xtPxM">note</a>')).toEqual(["~relation", "=", "#root/RclIpMauTOKS/NFi2gL4xtPxM"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("use quotes to define value", () => {
|
||||||
|
expect(attributeParser.lexer("#'label a'='hello\"` world'"))
|
||||||
|
.toEqual(["#label a", "=", 'hello"` world']);
|
||||||
|
|
||||||
|
expect(attributeParser.lexer('#"label a" = "hello\'` world"'))
|
||||||
|
.toEqual(["#label a", "=", "hello'` world"]);
|
||||||
|
|
||||||
|
expect(attributeParser.lexer('#`label a` = `hello\'" world`'))
|
||||||
|
.toEqual(["#label a", "=", "hello'\" world"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Parser", () => {
|
||||||
|
it("simple label", () => {
|
||||||
|
const attrs = attributeParser.parser(["#token"]);
|
||||||
|
|
||||||
|
expect(attrs.length).toEqual(1);
|
||||||
|
expect(attrs[0].type).toEqual('label');
|
||||||
|
expect(attrs[0].name).toEqual('token');
|
||||||
|
expect(attrs[0].value).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("label with value", () => {
|
||||||
|
const attrs = attributeParser.parser(["#token", "=", "val"]);
|
||||||
|
|
||||||
|
expect(attrs.length).toEqual(1);
|
||||||
|
expect(attrs[0].type).toEqual('label');
|
||||||
|
expect(attrs[0].name).toEqual('token');
|
||||||
|
expect(attrs[0].value).toEqual("val");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("relation", () => {
|
||||||
|
const attrs = attributeParser.parser(["~token", "=", "#root/RclIpMauTOKS/NFi2gL4xtPxM"]);
|
||||||
|
|
||||||
|
expect(attrs.length).toEqual(1);
|
||||||
|
expect(attrs[0].type).toEqual('relation');
|
||||||
|
expect(attrs[0].name).toEqual("token");
|
||||||
|
expect(attrs[0].value).toEqual('#root/RclIpMauTOKS/NFi2gL4xtPxM');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("error cases", () => {
|
||||||
|
expect(() => attributeParser.parser(["~token"])).toThrow('Relation "~token" should point to a note.');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
execute();
|
execute();
|
||||||
|
@ -25,6 +25,36 @@ export function expect(val) {
|
|||||||
|
|
||||||
errorCount++;
|
errorCount++;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
toBeFalsy: () => {
|
||||||
|
if (!!val) {
|
||||||
|
console.trace("toBeFalsy failed.");
|
||||||
|
console.error(`expected: null, false, undefined, 0 or empty string`);
|
||||||
|
console.error(`got: ${val}`);
|
||||||
|
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toThrow: errorMessage => {
|
||||||
|
try {
|
||||||
|
val();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (e.message !== errorMessage) {
|
||||||
|
console.trace("toThrow caught exception, but messages differ");
|
||||||
|
console.error(`expected: ${errorMessage}`);
|
||||||
|
console.error(`got: ${e.message}`);
|
||||||
|
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.trace("toThrow did not catch any exception.");
|
||||||
|
console.error(`expected: ${errorMessage}`);
|
||||||
|
console.error(`got: [none]`);
|
||||||
|
errorCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
|
function preprocessRelations(str) {
|
||||||
|
return str.replace(/<a[^>]+href="(#root[A-Za-z0-9/]*)"[^>]*>[^<]*<\/a>/g, "$1");
|
||||||
|
}
|
||||||
|
|
||||||
function lexer(str) {
|
function lexer(str) {
|
||||||
str = str.toLowerCase();
|
str = preprocessRelations(str);
|
||||||
|
|
||||||
const expressionTokens = [];
|
const expressionTokens = [];
|
||||||
|
|
||||||
@ -95,6 +99,55 @@ function lexer(str) {
|
|||||||
return expressionTokens;
|
return expressionTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
function parser(tokens) {
|
||||||
lexer
|
const attrs = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
|
const token = tokens[i];
|
||||||
|
|
||||||
|
if (token.startsWith('#')) {
|
||||||
|
const attr = {
|
||||||
|
type: 'label',
|
||||||
|
name: token.substr(1)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tokens[i + 1] === "=") {
|
||||||
|
if (i + 2 >= tokens.length) {
|
||||||
|
throw new Error(`Missing value for label "${token}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 2;
|
||||||
|
|
||||||
|
attr.value = tokens[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs.push(attr);
|
||||||
|
}
|
||||||
|
else if (token.startsWith('~')) {
|
||||||
|
const attr = {
|
||||||
|
type: 'relation',
|
||||||
|
name: token.substr(1)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (i + 2 >= tokens.length || tokens[i + 1] !== '=') {
|
||||||
|
throw new Error(`Relation "${token}" should point to a note.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 2;
|
||||||
|
|
||||||
|
attr.value = tokens[i];
|
||||||
|
|
||||||
|
attrs.push(attr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error(`Unrecognized attribute "${token}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
lexer,
|
||||||
|
parser
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const noteCache = require('./note_cache');
|
const noteCache = require('./note_cache');
|
||||||
const hoistedNoteService = require('../hoisted_note');
|
const hoistedNoteService = require('../hoisted_note');
|
||||||
|
const protectedSessionService = require('../protected_session');
|
||||||
const stringSimilarity = require('string-similarity');
|
const stringSimilarity = require('string-similarity');
|
||||||
|
|
||||||
function isNotePathArchived(notePath) {
|
function isNotePathArchived(notePath) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user