mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	attribute parser and tests WIP
This commit is contained in:
		| @@ -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) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user