feat: external API for registering views and custom functions. Added subproject for publishing npm package with types for external plugins.

This commit is contained in:
Kacper Kula 2025-01-29 22:36:19 +00:00
parent 18941135ff
commit bc597400c6
29 changed files with 723 additions and 206 deletions

View file

@ -41,9 +41,13 @@
},
"dependencies": {
"@ag-grid-community/theming": "^32.3.3",
"@codemirror/language": "^6.10.8",
"@codemirror/state": "^6.5.1",
"@codemirror/view": "^6.36.2",
"@hypersphere/omnibus": "^0.1.6",
"@jlongster/sql.js": "^1.6.7",
"@types/jsonpath": "^0.2.4",
"@vanakat/plugin-api": "^0.2.1",
"absurd-sql": "^0.0.54",
"ag-grid-community": "^32.3.3",
"comlink": "^4.4.2",

View file

@ -11,6 +11,15 @@ importers:
'@ag-grid-community/theming':
specifier: ^32.3.3
version: 32.3.3
'@codemirror/language':
specifier: ^6.10.8
version: 6.10.8
'@codemirror/state':
specifier: ^6.5.1
version: 6.5.1
'@codemirror/view':
specifier: ^6.36.2
version: 6.36.2
'@hypersphere/omnibus':
specifier: ^0.1.6
version: 0.1.6
@ -20,6 +29,9 @@ importers:
'@types/jsonpath':
specifier: ^0.2.4
version: 0.2.4
'@vanakat/plugin-api':
specifier: ^0.2.1
version: 0.2.1(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)(eslint@9.15.0)
absurd-sql:
specifier: ^0.0.54
version: 0.0.54
@ -95,7 +107,7 @@ importers:
version: 29.7.0(@types/node@22.9.3)
obsidian:
specifier: ^1.7.2
version: 1.7.2(@codemirror/state@6.4.1)(@codemirror/view@6.35.0)
version: 1.7.2(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)
prettier:
specifier: 3.3.3
version: 3.3.3
@ -360,11 +372,14 @@ packages:
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
'@codemirror/state@6.4.1':
resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==}
'@codemirror/language@6.10.8':
resolution: {integrity: sha512-wcP8XPPhDH2vTqf181U8MbZnW+tDyPYy0UzVOa+oHORjyT+mhhom9vBd7dApJwoDz9Nb/a8kHjJIsuA/t8vNFw==}
'@codemirror/view@6.35.0':
resolution: {integrity: sha512-I0tYy63q5XkaWsJ8QRv5h6ves7kvtrBWjBcnf/bzohFJQc5c14a1AQRdE8QpPF9eMp5Mq2FMm59TCj1gDfE7kw==}
'@codemirror/state@6.5.1':
resolution: {integrity: sha512-3rA9lcwciEB47ZevqvD8qgbzhM9qMb8vCcQCNmDfVRPQG4JT9mSb0Jg8H7YjKGGQcFnLN323fj9jdnG59Kx6bg==}
'@codemirror/view@6.36.2':
resolution: {integrity: sha512-DZ6ONbs8qdJK0fdN7AB82CgI6tYXf4HWk1wSVa0+9bhVznCuuvhQtX8bFBoy3dv8rZSQqUd8GvhVAcielcidrA==}
'@docsearch/css@3.8.0':
resolution: {integrity: sha512-pieeipSOW4sQ0+bE5UFC51AOZp9NGxg89wAlZ1BAQFaiRAGK1IKUaPQ0UGZeNctJXyqZ1UvBtOQh2HH+U5GtmA==}
@ -835,10 +850,22 @@ packages:
'@jspm/core@2.1.0':
resolution: {integrity: sha512-3sRl+pkyFY/kLmHl0cgHiFp2xEqErA8N3ECjMs7serSUBmoJ70lBa0PG5t0IM6WJgdZNyyI0R8YFfi5wM8+mzg==}
'@lezer/common@1.2.3':
resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==}
'@lezer/highlight@1.2.1':
resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==}
'@lezer/lr@1.4.2':
resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==}
'@malept/cross-spawn-promise@2.0.0':
resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==}
engines: {node: '>= 12.13.0'}
'@marijn/find-cluster-break@1.0.2':
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@ -1088,6 +1115,17 @@ packages:
'@types/yargs@17.0.33':
resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
'@typescript-eslint/eslint-plugin@7.18.0':
resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
'@typescript-eslint/parser': ^7.0.0
eslint: ^8.56.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
'@typescript-eslint/eslint-plugin@8.15.0':
resolution: {integrity: sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -1099,6 +1137,16 @@ packages:
typescript:
optional: true
'@typescript-eslint/parser@7.18.0':
resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
eslint: ^8.56.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
'@typescript-eslint/parser@8.15.0':
resolution: {integrity: sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -1109,10 +1157,24 @@ packages:
typescript:
optional: true
'@typescript-eslint/scope-manager@7.18.0':
resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/scope-manager@8.15.0':
resolution: {integrity: sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@7.18.0':
resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
eslint: ^8.56.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
'@typescript-eslint/type-utils@8.15.0':
resolution: {integrity: sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -1123,10 +1185,23 @@ packages:
typescript:
optional: true
'@typescript-eslint/types@7.18.0':
resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/types@8.15.0':
resolution: {integrity: sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@7.18.0':
resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
'@typescript-eslint/typescript-estree@8.15.0':
resolution: {integrity: sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -1136,6 +1211,12 @@ packages:
typescript:
optional: true
'@typescript-eslint/utils@7.18.0':
resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
eslint: ^8.56.0
'@typescript-eslint/utils@8.15.0':
resolution: {integrity: sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -1146,6 +1227,10 @@ packages:
typescript:
optional: true
'@typescript-eslint/visitor-keys@7.18.0':
resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/visitor-keys@8.15.0':
resolution: {integrity: sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -1153,6 +1238,9 @@ packages:
'@ungap/structured-clone@1.2.0':
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
'@vanakat/plugin-api@0.2.1':
resolution: {integrity: sha512-m2gVJFTPoIG+fUDAWYPPW/XoywBXrGtYOZFZdQHZmL62Zoc9NntCID76/Wu17DAanQ4aiZN8yRHHXlfq6sPvsQ==}
'@vitejs/plugin-vue@5.2.0':
resolution: {integrity: sha512-7n7KdUEtx/7Yl7I/WVAMZ1bEb0eVvXF3ummWTeLcs/9gvo9pJhuLdouSXGjdZ/MKD1acf1I272+X0RMua4/R3g==}
engines: {node: ^18.0.0 || >=20.0.0}
@ -1323,6 +1411,10 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
async@3.2.6:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
@ -1591,6 +1683,10 @@ packages:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
ejs@3.1.10:
resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
engines: {node: '>=0.10.0'}
@ -1876,6 +1972,10 @@ packages:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
globby@11.1.0:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
engines: {node: '>=10'}
gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
@ -2589,6 +2689,10 @@ packages:
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
perfect-debounce@1.0.0:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
@ -2967,6 +3071,11 @@ packages:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'}
typescript@5.4.5:
resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
engines: {node: '>=14.17'}
hasBin: true
typescript@5.7.2:
resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==}
engines: {node: '>=14.17'}
@ -3466,11 +3575,22 @@ snapshots:
'@bcoe/v8-coverage@0.2.3': {}
'@codemirror/state@6.4.1': {}
'@codemirror/view@6.35.0':
'@codemirror/language@6.10.8':
dependencies:
'@codemirror/state': 6.4.1
'@codemirror/state': 6.5.1
'@codemirror/view': 6.36.2
'@lezer/common': 1.2.3
'@lezer/highlight': 1.2.1
'@lezer/lr': 1.4.2
style-mod: 4.1.2
'@codemirror/state@6.5.1':
dependencies:
'@marijn/find-cluster-break': 1.0.2
'@codemirror/view@6.36.2':
dependencies:
'@codemirror/state': 6.5.1
style-mod: 4.1.2
w3c-keyname: 2.2.8
@ -3894,10 +4014,22 @@ snapshots:
'@jspm/core@2.1.0': {}
'@lezer/common@1.2.3': {}
'@lezer/highlight@1.2.1':
dependencies:
'@lezer/common': 1.2.3
'@lezer/lr@1.4.2':
dependencies:
'@lezer/common': 1.2.3
'@malept/cross-spawn-promise@2.0.0':
dependencies:
cross-spawn: 7.0.6
'@marijn/find-cluster-break@1.0.2': {}
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
@ -4140,6 +4272,24 @@ snapshots:
dependencies:
'@types/yargs-parser': 21.0.3
'@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.15.0)(typescript@5.4.5))(eslint@9.15.0)(typescript@5.4.5)':
dependencies:
'@eslint-community/regexpp': 4.12.1
'@typescript-eslint/parser': 7.18.0(eslint@9.15.0)(typescript@5.4.5)
'@typescript-eslint/scope-manager': 7.18.0
'@typescript-eslint/type-utils': 7.18.0(eslint@9.15.0)(typescript@5.4.5)
'@typescript-eslint/utils': 7.18.0(eslint@9.15.0)(typescript@5.4.5)
'@typescript-eslint/visitor-keys': 7.18.0
eslint: 9.15.0
graphemer: 1.4.0
ignore: 5.3.2
natural-compare: 1.4.0
ts-api-utils: 1.4.0(typescript@5.4.5)
optionalDependencies:
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
'@typescript-eslint/eslint-plugin@8.15.0(@typescript-eslint/parser@8.15.0(eslint@9.15.0)(typescript@5.7.2))(eslint@9.15.0)(typescript@5.7.2)':
dependencies:
'@eslint-community/regexpp': 4.12.1
@ -4158,6 +4308,19 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@7.18.0(eslint@9.15.0)(typescript@5.4.5)':
dependencies:
'@typescript-eslint/scope-manager': 7.18.0
'@typescript-eslint/types': 7.18.0
'@typescript-eslint/typescript-estree': 7.18.0(typescript@5.4.5)
'@typescript-eslint/visitor-keys': 7.18.0
debug: 4.3.7
eslint: 9.15.0
optionalDependencies:
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.15.0(eslint@9.15.0)(typescript@5.7.2)':
dependencies:
'@typescript-eslint/scope-manager': 8.15.0
@ -4171,11 +4334,28 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@7.18.0':
dependencies:
'@typescript-eslint/types': 7.18.0
'@typescript-eslint/visitor-keys': 7.18.0
'@typescript-eslint/scope-manager@8.15.0':
dependencies:
'@typescript-eslint/types': 8.15.0
'@typescript-eslint/visitor-keys': 8.15.0
'@typescript-eslint/type-utils@7.18.0(eslint@9.15.0)(typescript@5.4.5)':
dependencies:
'@typescript-eslint/typescript-estree': 7.18.0(typescript@5.4.5)
'@typescript-eslint/utils': 7.18.0(eslint@9.15.0)(typescript@5.4.5)
debug: 4.3.7
eslint: 9.15.0
ts-api-utils: 1.4.0(typescript@5.4.5)
optionalDependencies:
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
'@typescript-eslint/type-utils@8.15.0(eslint@9.15.0)(typescript@5.7.2)':
dependencies:
'@typescript-eslint/typescript-estree': 8.15.0(typescript@5.7.2)
@ -4188,8 +4368,25 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@7.18.0': {}
'@typescript-eslint/types@8.15.0': {}
'@typescript-eslint/typescript-estree@7.18.0(typescript@5.4.5)':
dependencies:
'@typescript-eslint/types': 7.18.0
'@typescript-eslint/visitor-keys': 7.18.0
debug: 4.3.7
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.6.3
ts-api-utils: 1.4.0(typescript@5.4.5)
optionalDependencies:
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
'@typescript-eslint/typescript-estree@8.15.0(typescript@5.7.2)':
dependencies:
'@typescript-eslint/types': 8.15.0
@ -4205,6 +4402,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@7.18.0(eslint@9.15.0)(typescript@5.4.5)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.15.0)
'@typescript-eslint/scope-manager': 7.18.0
'@typescript-eslint/types': 7.18.0
'@typescript-eslint/typescript-estree': 7.18.0(typescript@5.4.5)
eslint: 9.15.0
transitivePeerDependencies:
- supports-color
- typescript
'@typescript-eslint/utils@8.15.0(eslint@9.15.0)(typescript@5.7.2)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.15.0)
@ -4217,6 +4425,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/visitor-keys@7.18.0':
dependencies:
'@typescript-eslint/types': 7.18.0
eslint-visitor-keys: 3.4.3
'@typescript-eslint/visitor-keys@8.15.0':
dependencies:
'@typescript-eslint/types': 8.15.0
@ -4224,6 +4437,18 @@ snapshots:
'@ungap/structured-clone@1.2.0': {}
'@vanakat/plugin-api@0.2.1(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)(eslint@9.15.0)':
dependencies:
'@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.15.0)(typescript@5.4.5))(eslint@9.15.0)(typescript@5.4.5)
'@typescript-eslint/parser': 7.18.0(eslint@9.15.0)(typescript@5.4.5)
obsidian: 1.7.2(@codemirror/state@6.5.1)(@codemirror/view@6.36.2)
typescript: 5.4.5
transitivePeerDependencies:
- '@codemirror/state'
- '@codemirror/view'
- eslint
- supports-color
'@vitejs/plugin-vue@5.2.0(vite@5.4.11(@types/node@22.9.3))(vue@3.5.13(typescript@5.7.2))':
dependencies:
vite: 5.4.11(@types/node@22.9.3)
@ -4417,6 +4642,8 @@ snapshots:
argparse@2.0.1: {}
array-union@2.1.0: {}
async@3.2.6: {}
available-typed-arrays@1.0.7:
@ -4706,6 +4933,10 @@ snapshots:
diff-sequences@29.6.3: {}
dir-glob@3.0.1:
dependencies:
path-type: 4.0.0
ejs@3.1.10:
dependencies:
jake: 10.9.2
@ -5075,6 +5306,15 @@ snapshots:
globals@14.0.0: {}
globby@11.1.0:
dependencies:
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.3.2
ignore: 5.3.2
merge2: 1.4.1
slash: 3.0.0
gopd@1.0.1:
dependencies:
get-intrinsic: 1.2.4
@ -5902,10 +6142,10 @@ snapshots:
gauge: 4.0.4
set-blocking: 2.0.0
obsidian@1.7.2(@codemirror/state@6.4.1)(@codemirror/view@6.35.0):
obsidian@1.7.2(@codemirror/state@6.5.1)(@codemirror/view@6.36.2):
dependencies:
'@codemirror/state': 6.4.1
'@codemirror/view': 6.35.0
'@codemirror/state': 6.5.1
'@codemirror/view': 6.36.2
'@types/codemirror': 5.60.8
moment: 2.29.4
@ -5998,6 +6238,8 @@ snapshots:
path-parse@1.0.7: {}
path-type@4.0.0: {}
perfect-debounce@1.0.0: {}
picocolors@1.1.1: {}
@ -6308,6 +6550,10 @@ snapshots:
trim-lines@3.0.1: {}
ts-api-utils@1.4.0(typescript@5.4.5):
dependencies:
typescript: 5.4.5
ts-api-utils@1.4.0(typescript@5.7.2):
dependencies:
typescript: 5.7.2
@ -6346,6 +6592,8 @@ snapshots:
type-fest@0.21.3: {}
typescript@5.4.5: {}
typescript@5.7.2: {}
underscore@1.12.1: {}

56
src/cellParser.ts Normal file
View file

@ -0,0 +1,56 @@
import { Database } from "sql.js";
import { parse } from 'json5'
import { SqlSealDatabase } from "./database/database";
export interface CellParser {
render: (content: string) => Node | string;
}
export class CellParserRegistar implements CellParser {
functions: Map<string, any> = new Map()
constructor(private db: SqlSealDatabase) {
}
register(name: string, fn: any, argsCount = 1) {
if (this.functions.has(name)) {
throw new Error('Function with that name already exists: ' + name)
}
this.functions.set(name, fn)
this.db.registerCustomFunction(name, argsCount)
}
unregister(name: string) {
this.functions.delete(name)
}
private renderCustomElement(el: any): Node | string {
if (this.functions.has(el.type)) {
return this.functions.get(el.type)!(el.values)
} else {
throw new Error(`Custom function processor ${el.type} is not registered`)
}
}
render(content: string) {
try {
if (!content) {
return content
}
if (typeof content !== 'string') {
return content
}
if (content.startsWith('SQLSEALCUSTOM')) {
const parsedData = parse(content.slice('SQLSEALCUSTOM('.length, -1))
return this.renderCustomElement(parsedData)
}
return content
} catch (e) {
console.error('Error parsing cell with data:', content, e)
return createDiv({
text: 'Parsing error',
cls: 'sqlseal-parse-error'
})
}
}
}

View file

@ -1,13 +1,13 @@
import { OmnibusRegistrator } from "@hypersphere/omnibus";
import { App, MarkdownPostProcessorContext, MarkdownRenderChild, TFile } from "obsidian";
import { SqlSealDatabase } from "src/database/database";
import { Sync } from "src/datamodel/sync";
import { ParserTableDefinition } from "src/datamodel/syncStrategy/types";
import { parseLanguage } from "src/grammar/newParser";
import { RendererRegistry, RenderReturn } from "src/renderer/rendererRegistry";
import { transformQuery } from "src/sql/sqlTransformer";
import { registerObservers } from "src/utils/registerObservers";
import { displayError, displayNotice } from "src/utils/ui";
import { SqlSealDatabase } from "../database/database";
import { Sync } from "../datamodel/sync";
import { ParserTableDefinition } from "../datamodel/syncStrategy/types";
import { parseLanguage } from "../grammar/newParser";
import { RendererRegistry, RenderReturn } from "../renderer/rendererRegistry";
import { transformQuery } from "../sql/sqlTransformer";
import { registerObservers } from "../utils/registerObservers";
import { displayError, displayNotice } from "../utils/ui";
export class CodeblockProcessor extends MarkdownRenderChild {

View file

@ -1,7 +1,7 @@
import { App, MarkdownPostProcessorContext } from "obsidian";
import { InlineProcessor } from "./InlineProcessor";
import { SqlSealDatabase } from "src/database/database";
import { Sync } from "src/datamodel/sync";
import { SqlSealDatabase } from "../../database/database";
import { Sync } from "../../datamodel/sync";
export class SqlSealInlineHandler {
constructor(

View file

@ -1,11 +1,11 @@
import { OmnibusRegistrator } from "@hypersphere/omnibus";
import { App, MarkdownRenderChild } from "obsidian";
import { SqlSealDatabase } from "src/database/database";
import { Sync } from "src/datamodel/sync";
import { RenderReturn } from "src/renderer/rendererRegistry";
import { transformQuery } from "src/sql/sqlTransformer";
import { registerObservers } from "src/utils/registerObservers";
import { displayError } from "src/utils/ui";
import { SqlSealDatabase } from "../../database/database";
import { Sync } from "../../datamodel/sync";
import { RenderReturn } from "../../renderer/rendererRegistry";
import { transformQuery } from "../../sql/sqlTransformer";
import { registerObservers } from "../../utils/registerObservers";
import { displayError } from "../../utils/ui";
export class InlineProcessor extends MarkdownRenderChild {
private registrator: OmnibusRegistrator;

View file

@ -1,5 +1,6 @@
import { App } from "obsidian"
import * as Comlink from 'comlink'
// @ts-ignore
import workerCode from 'virtual:worker-code'
import { WorkerDatabase } from "./worker/database";
@ -11,6 +12,10 @@ export class SqlSealDatabase {
}
registerCustomFunction(name: string, argsCount = 1) {
return this.db.registerCustomFunction(name, argsCount)
}
async connect() {
if (this.isConnected) {
return Promise.resolve()

View file

@ -1,12 +1,12 @@
import * as Comlink from "comlink"
import initSqlJs from '@jlongster/sql.js';
// @ts-ignore
import wasmBinary from '../../../node_modules/@jlongster/sql.js/dist/sql-wasm.wasm'
import { SQLiteFS } from 'absurd-sql';
import IndexedDBBackend from '../../../node_modules/absurd-sql/dist/indexeddb-backend.js';
import type { BindParams, Database, Statement } from "sql.js";
import { sanitise } from "../../utils/sanitiseColumn";
import { uniq } from "lodash";
import { createLoggingArrayProxy } from "src/utils/logArrayProxy";
function toObjectArray(stmt: Statement) {
@ -60,49 +60,28 @@ export class WorkerDatabase {
}
defineCustomFunctions() {
this.db.create_function('a', (href: string, name: string) => {
const linkObject = {
type: 'link',
href: href,
name: name || href
};
return `SQLSEALCUSTOM(${JSON.stringify(linkObject)})`;
});
this.db.create_function('a', (href: string) => {
const linkObject = {
type: 'link',
href: href,
name: href
};
return `SQLSEALCUSTOM(${JSON.stringify(linkObject)})`;
});
this.db.create_function('img', (href: string) => {
const imgObject = {
type: 'img',
href: href
registerCustomFunction(name: string, argsCount = 1) {
const fn = (...arg: string[]) => {
const data = {
type: name,
values: arg
}
return `SQLSEALCUSTOM(${JSON.stringify(imgObject)})`
})
return `SQLSEALCUSTOM(${JSON.stringify(data)})`
}
this.db.create_function('img', (href: string, path: string) => {
const imgObject = {
type: 'img',
path,
href
}
return `SQLSEALCUSTOM(${JSON.stringify(imgObject)})`
})
this.db.create_function('checkbox', (val: string) => {
const imgObject = {
type: 'checkbox',
value: val
}
return `SQLSEALCUSTOM(${JSON.stringify(imgObject)})`
})
// This is such a stupid solution but number of arguments needs to be static so SQLite understands which overload to use.
if (argsCount >= 1) {
this.db.create_function(name, (a: string) => fn(a))
}
if (argsCount >= 2) {
this.db.create_function(name, (a: string, b: string) => fn(a, b))
}
if (argsCount >= 3) {
this.db.create_function(name, (a: string, b: string, c: string) => fn(a, b, c))
}
if (argsCount >= 4) {
throw new Error('Too many arguments, only up to 3 arguments are supported at the moment.')
}
}
createTableText(tableName: string, fields: string[]) {
@ -227,7 +206,6 @@ export class WorkerDatabase {
VACUUM;
`);
this.db = db
this.defineCustomFunctions()
return
} catch (e) {
console.error('Error while setting up database', e);

View file

@ -1,4 +1,4 @@
import { SqlSealDatabase } from "src/database/database";
import { SqlSealDatabase } from "../../database/database";
export abstract class Repository {
constructor(protected readonly db: SqlSealDatabase) { }

View file

@ -1,4 +1,4 @@
import { SqlSealDatabase } from "src/database/database";
import { SqlSealDatabase } from "../database/database";
import { TableAliasesRepository } from "./repository/tableAliases";
import { App, TAbstractFile, TFile, Vault } from "obsidian";
import { FilepathHasher } from "../utils/hasher";

View file

@ -4,8 +4,8 @@ import { syntaxTree } from "@codemirror/language";
import { App } from "obsidian";
import { SqlSealDatabase } from "../database/database";
import { Sync } from "../datamodel/sync";
import { SqlSealInlineHandler } from "src/codeblockHandler/inline/InlineCodeHandler";
import { InlineProcessor } from "src/codeblockHandler/inline/InlineProcessor";
import { SqlSealInlineHandler } from "../codeblockHandler/inline/InlineCodeHandler";
import { InlineProcessor } from "../codeblockHandler/inline/InlineProcessor";
export function createSqlSealEditorExtension(
app: App,

View file

@ -1,26 +1,26 @@
import { Menu, Plugin, TAbstractFile, Tasks, TFile } from 'obsidian';
import { GridRenderer } from 'src/renderer/GridRenderer';
import { MarkdownRenderer } from 'src/renderer/MarkdownRenderer';
import { TableRenderer } from 'src/renderer/TableRenderer';
import { RendererConfig, RendererRegistry } from 'src/renderer/rendererRegistry';
import { DEFAULT_SETTINGS, SQLSealSettings, SQLSealSettingsTab } from 'src/settings/SQLSealSettingsTab';
import { SqlSeal } from 'src/sqlSeal';
import { SealFileSync } from 'src/vaultSync/SealFileSync';
import { FilesFileSyncTable } from 'src/vaultSync/tables/filesTable';
import { TagsFileSyncTable } from 'src/vaultSync/tables/tagsTable';
import { TasksFileSyncTable } from 'src/vaultSync/tables/tasksTable';
import { CSV_VIEW_EXTENSIONS, CSV_VIEW_TYPE, CSVView } from 'src/view/CSVView';
import { GridRenderer } from './renderer/GridRenderer';
import { MarkdownRenderer } from './renderer/MarkdownRenderer';
import { TableRenderer } from './renderer/TableRenderer';
import { RendererConfig, RendererRegistry } from './renderer/rendererRegistry';
import { DEFAULT_SETTINGS, SQLSealSettings, SQLSealSettingsTab } from './settings/SQLSealSettingsTab';
import { SqlSeal } from './sqlSeal';
import { SealFileSync } from './vaultSync/SealFileSync';
import { CSV_VIEW_EXTENSIONS, CSV_VIEW_TYPE, CSVView } from './view/CSVView';
import { createSqlSealEditorExtension } from './editorExtension/inlineCodeBlock';
import { ListRenderer } from './renderer/ListRenderer';
import { JSON_VIEW_EXTENSIONS, JSON_VIEW_TYPE, JsonView } from './view/JsonView';
const GLOBAL_KEY = 'sqlSealApi'
import { CellParserRegistar } from './cellParser';
import { registerAPI } from '@vanakat/plugin-api';
import { SQLSealRegisterApi } from './pluginApi/sqlSealApi';
import { registerDefaultFunctions } from './utils/ui';
export default class SqlSealPlugin extends Plugin {
settings: SQLSealSettings;
fileSync: SealFileSync;
sqlSeal: SqlSeal;
rendererRegistry: RendererRegistry = new RendererRegistry();
cellParserRegistar: CellParserRegistar;
async onload() {
await this.loadSettings();
@ -35,16 +35,21 @@ export default class SqlSealPlugin extends Plugin {
await this.registerViews();
await this.registerSQLSealExtensions()
this.rendererRegistry.register('sql-seal-internal-table', new TableRenderer(this.app))
this.rendererRegistry.register('sql-seal-internal-grid', new GridRenderer(this.app))
this.rendererRegistry.register('sql-seal-internal-markdown', new MarkdownRenderer(this.app))
this.rendererRegistry.register('sql-seal-internal-list', new ListRenderer(this.app))
this.registerGlobalApi();
const sqlSeal = new SqlSeal(this.app, false, this.rendererRegistry) // FIXME: set verbose based on the env.
this.sqlSeal = sqlSeal
await this.sqlSeal.db.connect()
this.cellParserRegistar = new CellParserRegistar(this.sqlSeal.db)
registerDefaultFunctions(this.cellParserRegistar, this.app)
// REGISTERING VIEWS
this.rendererRegistry.register('sql-seal-internal-table', new TableRenderer(this.app, this.cellParserRegistar))
this.rendererRegistry.register('sql-seal-internal-grid', new GridRenderer(this.app, this.cellParserRegistar))
this.rendererRegistry.register('sql-seal-internal-markdown', new MarkdownRenderer(this.app))
this.rendererRegistry.register('sql-seal-internal-list', new ListRenderer(this.app, this.cellParserRegistar))
// start syncing when files are loaded
this.app.workspace.onLayoutReady(async () => {
@ -158,7 +163,7 @@ export default class SqlSealPlugin extends Plugin {
async registerViews() {
this.registerView(
CSV_VIEW_TYPE,
(leaf) => new CSVView(leaf, this.settings.enableEditing)
(leaf) => new CSVView(leaf, this.settings.enableEditing, this.cellParserRegistar)
);
this.registerView(
JSON_VIEW_TYPE,
@ -166,26 +171,29 @@ export default class SqlSealPlugin extends Plugin {
)
}
registerGlobalApi() {
(window as any)[GLOBAL_KEY] = {
registerRenderer: (uniqueName: string, config: RendererConfig) => {
this.rendererRegistry.register(uniqueName, config)
},
unregisterRenderer: (uniqueName: string) => {
this.rendererRegistry.unregister(uniqueName)
}
}
registerSQLSealView(name: string, config: RendererConfig) {
this.rendererRegistry.register(name, config)
}
unregisterGlobalApi() {
(window as any)[GLOBAL_KEY] = undefined
unregisterSQLSealView(name: string) {
this.rendererRegistry.unregister(name)
}
registerSQLSealFunction(name: string, fn: any, argumentsCount: number = 1) {
this.cellParserRegistar.register(name, fn, argumentsCount)
}
unregisterSQLSealFunction(name: string) {
this.cellParserRegistar.unregister(name)
}
registerGlobalApi() {
registerAPI('sqlseal', new SQLSealRegisterApi(this), this)
}
onunload() {
this.sqlSeal.db.disconect();
this.unregisterSQLSealExtensions();
this.unregisterGlobalApi();
}
async loadSettings() {

View file

@ -0,0 +1,80 @@
import { Plugin } from "obsidian"
import SqlSealPlugin from "../main"
import { version } from '../../package.json'
import { RendererConfig } from "../renderer/rendererRegistry";
const API_VERSION = 1;
export class SQLSealRegisterApi {
registeredApis: Array<SQLSealApi> = []
constructor(private sqlSealPlugin: SqlSealPlugin) {
sqlSealPlugin.register(() => {
this.registeredApis.forEach(p => {
p.unregister()
})
this.registeredApis = []
})
}
get sqlSealVersion() {
return version
}
get apiVersion() {
return API_VERSION
}
registerForPlugin(plugin: Plugin) {
const api = new SQLSealApi(plugin, this.sqlSealPlugin)
this.registeredApis.push(api)
return api
}
}
interface RegisteredView {
name: string;
viewClass: any;
}
interface RegisteredFunction {
name: string,
fn: CallableFunction
}
export class SQLSealApi {
private views: Array<RegisteredView> = []
private functions: Array<RegisteredFunction> = []
constructor(private readonly plugin: Plugin, private sqlSealPlugin: SqlSealPlugin) {
plugin.register(() => {
this.unregister()
})
}
registerView(name: string, viewClass: RendererConfig) {
this.views.push({
name,
viewClass
})
this.sqlSealPlugin.registerSQLSealView(name, viewClass)
}
registerCustomFunction(name: string, fn: CallableFunction, argumentsCount: number = 1) {
this.functions.push({
name,
fn,
})
this.sqlSealPlugin.registerSQLSealFunction(name, fn, argumentsCount)
}
unregister() {
for(const view of this.views) {
this.sqlSealPlugin.unregisterSQLSealView(view.name)
}
this.views = []
for(const fn of this.functions) {
this.sqlSealPlugin.unregisterSQLSealFunction(fn.name)
}
}
}

View file

@ -1,9 +1,9 @@
import { createGrid, GridApi, GridOptions, themeQuartz } from "ag-grid-community";
import { merge } from "lodash";
import { App } from "obsidian";
import { RendererConfig } from "src/renderer/rendererRegistry";
import { RendererConfig } from "./rendererRegistry";
import { parse } from 'json5'
import { parseCell } from "src/utils/ui";
import { CellParser } from "../cellParser";
const getCurrentTheme = () => {
return document.body.classList.contains('theme-dark') ? 'dark' : 'light';
@ -24,7 +24,12 @@ const getAgGridTheme = (theme: 'dark' | 'light') => {
}
class GridRendererCommunicator {
constructor(private el: HTMLElement, private config: Partial<GridOptions>, private app: App) {
constructor(
private el: HTMLElement,
private config: Partial<GridOptions>,
private app: App,
private cellParser: CellParser
) {
this.initialize()
}
@ -62,7 +67,7 @@ class GridRendererCommunicator {
resizable: false,
cellRendererSelector: () => {
return {
component: ({ value }: { value: string }) => parseCell(value, this.app)
component: ({ value }: { value: string }) => this.cellParser.render(value)
}
},
autoHeight: true
@ -109,7 +114,7 @@ class GridRendererCommunicator {
}
export class GridRenderer implements RendererConfig {
constructor(private app: App) { }
constructor(private app: App, private readonly cellParser: CellParser) { }
get rendererKey() {
return 'grid'
}
@ -125,7 +130,7 @@ export class GridRenderer implements RendererConfig {
render(config: Partial<GridOptions>, el: HTMLElement) {
const communicator = new GridRendererCommunicator(el, config, this.app)
const communicator = new GridRendererCommunicator(el, config, this.app, this.cellParser)
return {
render: (data: any) => {
// FIXME: we need to update that.

View file

@ -1,7 +1,8 @@
// This is renderer for a very basic List view.
import { App } from "obsidian";
import { RendererConfig } from "src/renderer/rendererRegistry";
import { displayError, parseCell } from "src/utils/ui";
import { CellParser } from "../cellParser";
import { RendererConfig } from "../renderer/rendererRegistry";
import { displayError } from "../utils/ui";
interface ListRendererConfig {
classNames: string[]
@ -9,7 +10,7 @@ interface ListRendererConfig {
export class ListRenderer implements RendererConfig {
constructor(private readonly app: App) { }
constructor(private readonly app: App, private readonly cellParser: CellParser) { }
get rendererKey() {
return 'list'
@ -47,7 +48,7 @@ export class ListRenderer implements RendererConfig {
text: createEl('span', { text: c, cls: 'sqlseal-column-name' }) as any, // FIXME: this should be properly typed
cls: ['sqlseal-list-element-single']
})
const val = parseCell(d[c], this.app)
const val = this.cellParser.render(d[c])
el.append(val)
el.dataset.sqlsealColumn = c
})

View file

@ -1,8 +1,8 @@
// This is renderer for a very basic Table view.
import { getMarkdownTable } from "markdown-table-ts";
import { App } from "obsidian";
import { RendererConfig } from "src/renderer/rendererRegistry";
import { displayError, parseCell } from "src/utils/ui";
import { RendererConfig } from "../renderer/rendererRegistry";
import { displayError } from "../utils/ui";
const mapDataFromHeaders = (columns: string[], data: Record<string, any>[]) => {
return data.map(d => columns.map(c => String(d[c])))

View file

@ -1,7 +1,8 @@
// This is renderer for a very basic Table view.
import { App } from "obsidian";
import { RendererConfig } from "src/renderer/rendererRegistry";
import { displayError, parseCell } from "src/utils/ui";
import { CellParser } from "../cellParser";
import { RendererConfig } from "../renderer/rendererRegistry";
import { displayError } from "../utils/ui";
interface HTMLRendererConfig {
classNames: string[]
@ -9,7 +10,7 @@ interface HTMLRendererConfig {
export class TableRenderer implements RendererConfig {
constructor(private readonly app: App) { }
constructor(private readonly app: App, private cellParser: CellParser) { }
get rendererKey() {
return 'html'
@ -51,7 +52,7 @@ export class TableRenderer implements RendererConfig {
data.forEach((d: any) => {
const row = body.createEl("tr")
columns.forEach((c: any) => {
row.createEl("td", { text: parseCell(d[c], this.app) as string })
row.createEl("td", { text: this.cellParser.render(d[c]) as string })
})
})

View file

@ -1,3 +1,5 @@
import { App } from "obsidian";
export interface DataFormat {
data: Record<string, any>[],
columns: string[]

View file

@ -1,56 +1,37 @@
import { App } from "obsidian"
import { CellParserRegistar } from "src/cellParser"
export const displayNotice = (el: HTMLElement, text: string) => {
el.empty()
el.createDiv({ text: text, cls: 'sqlseal-notice' })
}
export const displayError= (el: HTMLElement, text: string) => {
export const displayError = (el: HTMLElement, text: string) => {
el.empty()
el.createDiv({ text: text, cls: 'sqlseal-error' })
}
export const parseCell = (data: string, app: App) => {
try {
if (data && typeof data === 'string' && data.startsWith('SQLSEALCUSTOM')) {
const parsedData = JSON.parse(data.slice('SQLSEALCUSTOM('.length, -1))
return renderSqlSealCustomElement(parsedData, app)
}
return data
} catch (e) {
console.error('Error parsing cell with data:', data, e)
return createDiv({
text: 'Parsing error',
cls: 'sqlseal-parse-error'
})
}
}
type SqlSealAnchorElement = {
type: 'link',
href: string,
name: string
}
type SQLSealImgElement = {
type: 'img',
path?: string,
href: string
}
type SQLSealCheckboxElement = {
type: 'checkbox',
value: number
}
type SqlSealCustomElement = SqlSealAnchorElement | SQLSealImgElement | SQLSealCheckboxElement;
const isLinkLocal = (link: string) => !link?.trim().startsWith('http')
const generateLink = (config: SqlSealAnchorElement, app: App) => {
let href = config.href
if (isLinkLocal(config.href)) {
let fileHref = config.href
const renderCheckbox = (app: App) => ([value]: [string]) => {
const el = createEl('input', {
type: 'checkbox',
attr: {
disabled: true
},
})
if (!!value) {
el.checked = true
}
return el
}
const renderLink = (app: App) => ([name, href]: [string, string]) => {
if (!href) {
href = name
}
if (isLinkLocal(href)) {
let fileHref = href
if (fileHref.endsWith('.md')) {
fileHref = fileHref.slice(0, -3)
}
@ -58,41 +39,35 @@ const generateLink = (config: SqlSealAnchorElement, app: App) => {
const encodedPath = encodeURIComponent(fileHref);
href = `obsidian://open?vault=${vaultName}&file=${encodedPath}`;
}
const el = createEl('a', { text: config.name, href: href })
const el = createEl('a', { text: name, href: href })
return el
}
const renderSqlSealCustomElement = (customConfig: SqlSealCustomElement, app: App) => {
switch (customConfig.type) {
case 'link':
return generateLink(customConfig, app)
case 'img':
if (!isLinkLocal(customConfig.href)) {
return createEl('img', { attr: { src: customConfig.href } });
}
let href = (customConfig.href ?? '').trim()
if (href.startsWith('![[')) {
href = href.slice(3, -2)
}
let parentPath = ''
if (customConfig.path) {
const parent = app.vault.getFileByPath(customConfig.path)
if (parent) {
parentPath = parent.parent?.path ?? ''
}
}
const path = (customConfig?.path ? parentPath + '/' : '') + href
const file = app.vault.getFileByPath(path);
if (!file) {
return 'File does not exist'
}
return createEl('img', { attr: { src: app.vault.getResourcePath(file) } });
case 'checkbox':
const el = createEl('input', { type: 'checkbox' })
el.checked = !!customConfig.value
el.disabled = true
return el
default:
return 'Invalid Custom Element'
const renderImage = (app: App) => ([href, path]: [string, string]) => {
if (!isLinkLocal(href)) {
return createEl('img', { attr: { src: href } });
}
href = (href ?? '').trim()
if (href.startsWith('![[')) {
href = href.slice(3, -2)
}
let parentPath = ''
if (path) {
const parent = app.vault.getFileByPath(path)
if (parent) {
parentPath = parent.parent?.path ?? ''
}
}
path = (path ? parentPath + '/' : '') + href
const file = app.vault.getFileByPath(path);
if (!file) {
return 'File does not exist'
}
return createEl('img', { attr: { src: app.vault.getResourcePath(file) } });
}
export const registerDefaultFunctions = (registar: CellParserRegistar, app: App) => {
registar.register('checkbox', renderCheckbox(app), 1)
registar.register('a', renderLink(app), 2)
registar.register('img', renderImage(app), 2)
}

View file

@ -1,5 +1,5 @@
import { App, TFile } from "obsidian";
import { SqlSealDatabase } from "src/database/database";
import { SqlSealDatabase } from "../../database/database";
export abstract class AFileSyncTable {
constructor(

View file

@ -39,7 +39,6 @@ export class FilesFileSyncTable extends AFileSyncTable {
super(db, app)
}
async onFileModify(file: TFile): Promise<void> {
console.log('ON FILE MODIFY', file.name)
// we need to update the row
const frontmatter = extractFrontmatterFromFile(file, this.plugin)
const frontmatterWithFileData = fileData(file, frontmatter)

View file

@ -1,9 +1,10 @@
import { WorkspaceLeaf, TextFileView, Menu } from 'obsidian';
import { parse, unparse } from 'papaparse';
import { DeleteConfirmationModal } from 'src/modal/deleteConfirmationModal';
import { RenameColumnModal } from 'src/modal/renameColumnModal';
import { CodeSampleModal } from 'src/modal/showCodeSample';
import { GridRenderer } from 'src/renderer/GridRenderer';
import { DeleteConfirmationModal } from '../modal/deleteConfirmationModal';
import { RenameColumnModal } from '../modal/renameColumnModal';
import { CodeSampleModal } from '../modal/showCodeSample';
import { GridRenderer } from '../renderer/GridRenderer';
import { CellParser } from '../cellParser';
export const CSV_VIEW_TYPE = "csv-viewer" as const;
export const CSV_VIEW_EXTENSIONS = ['csv'];
@ -12,7 +13,11 @@ export class CSVView extends TextFileView {
private content: string;
private table: HTMLTableElement;
constructor(leaf: WorkspaceLeaf, private enableEditing: boolean) {
constructor(
leaf: WorkspaceLeaf,
private enableEditing: boolean,
private cellParser: CellParser
) {
super(leaf);
}
@ -161,7 +166,7 @@ export class CSVView extends TextFileView {
})
const grid = new GridRenderer(this.app)
const grid = new GridRenderer(this.app, this.cellParser)
const csvView = this;
const api = grid.render({
defaultColDef: {

View file

@ -5,8 +5,8 @@ export const JSON_VIEW_TYPE = "sqlseal-json-viewer";
export const JSON_VIEW_EXTENSIONS = ['json', 'json5'];
export class JsonView extends TextFileView {
private content: string;
private table: HTMLTableElement;
private content: string = '';
private table: HTMLTableElement | undefined = undefined;
constructor(leaf: WorkspaceLeaf) {
super(leaf);
@ -44,7 +44,7 @@ export class JsonView extends TextFileView {
clear(): void {
this.content = '';
this.table.empty();
this.table?.empty();
}
api: any = null;

View file

@ -11,6 +11,7 @@
"importHelpers": false,
"isolatedModules": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"types": [
"jest"
],

50
types-package/README.md Normal file
View file

@ -0,0 +1,50 @@
# SQLSeal Types Package
This package helps you type your external plugin that uses SQLSeal internally.
## Installation
```bash
npm install --save-dev @hypersphere/sqlseal
```
## Usage
Example usage from SQLSeal Charts library.
```typescript
import { Plugin } from 'obsidian';
import { ChartRenderer } from './chartRenderer';
import { pluginApi } from '@vanakat/plugin-api';
import type { SQLSealRegisterApi } from '@hypersphere/sqlseal'
export default class SQLSealCharts extends Plugin {
async onload() {
this.registerWithSQLSeal();
}
private registerWithSQLSeal() {
const api = pluginApi('sqlseal') as SQLSealRegisterApi
const registar = api.registerForPlugin(this)
registar.registerView('sqlseal-charts', new ChartRenderer(this.app))
}
}
```
Unregistering will be automatically done by SQLSeal when you unload your plugin so no need to implement custom `onunload()` logic.
## Checking SQLSeal Version
You can check current SQLSeal version by calling:
```typescript
const api = pluginApi('sqlseal') as SQLSealRegisterApi
console.log(api.sqlSealVersion) // i.e. '0.20.0'
```
## Checking SQLSeal Version
You can check current SQLSeal version by calling:
```typescript
const api = pluginApi('sqlseal') as SQLSealRegisterApi
if (api.apiVersion >= 2) {
// Targetting API 2+
} else {
console.log("Plugin is incompatible with SQLSeal installed. Please update SQLSeal to the latest version and try again")
}
```

View file

@ -0,0 +1,25 @@
{
"name": "@hypersphere/sqlseal",
"version": "0.21.0",
"description": "",
"types": "dist/types-package/src/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "tsc",
"prepare": "npm run build"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
"typescript": "^5.0.0"
},
"peerDependencies": {
"typescript": ">=4.0.0"
},
"keywords": [],
"author": "",
"license": "ISC"
}

View file

@ -0,0 +1,24 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
devDependencies:
typescript:
specifier: ^5.0.0
version: 5.7.3
packages:
typescript@5.7.3:
resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==}
engines: {node: '>=14.17'}
hasBin: true
snapshots:
typescript@5.7.3: {}

View file

@ -0,0 +1,9 @@
import type { SQLSealRegisterApi, SQLSealApi } from '../../src/pluginApi/sqlSealApi'
import { RendererConfig } from '../../src/renderer/rendererRegistry'
export type {
SQLSealApi,
SQLSealRegisterApi,
RendererConfig
}

View file

@ -0,0 +1,41 @@
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": true,
"sourceMap": true,
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
// Disable strict checks
"strict": false,
"noImplicitAny": false,
"strictNullChecks": false,
"strictFunctionTypes": false,
"strictBindCallApply": false,
"strictPropertyInitialization": false,
"noImplicitThis": false,
"useUnknownInCatchVariables": false,
// Additional relaxed settings
"skipLibCheck": true,
"noEmitOnError": false, // Generate types even if there are errors
"allowJs": true, // Allow JavaScript files to be compiled
"checkJs": false, // Don't type-check JavaScript files
"allowUnreachableCode": true,
"allowUnusedLabels": true,
"noFallthroughCasesInSwitch": false,
"noImplicitReturns": false,
"noUnusedLocals": false,
"noUnusedParameters": false
},
"include": [
"src/**/*",
],
"exclude": [
"node_modules",
"dist"
]
}