@alizarin/napi 2.0.0-alpha.90 → 2.0.0-alpha.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +1 -0
- package/__test__/index.mjs +7 -7
- package/{alizarin-napi-2.0.0-alpha.90.tgz → alizarin-napi-2.0.0-alpha.93.tgz} +0 -0
- package/alizarin-napi.darwin-arm64.node +0 -0
- package/alizarin-napi.darwin-x64.node +0 -0
- package/alizarin-napi.linux-x64-gnu.node +0 -0
- package/alizarin-napi.win32-x64-msvc.node +0 -0
- package/index.d.ts +46 -4
- package/index.js +5 -1
- package/package.json +4 -4
- package/src/instance_wrapper_napi.rs +227 -11
- package/src/lib.rs +29 -0
package/Cargo.toml
CHANGED
package/__test__/index.mjs
CHANGED
|
@@ -345,7 +345,7 @@ describe('NapiPseudoValue property names', () => {
|
|
|
345
345
|
|
|
346
346
|
// Create instance wrapper and load tiles
|
|
347
347
|
const instanceWrapper = new NapiResourceInstanceWrapper(resource.resourceinstance.graph_id);
|
|
348
|
-
instanceWrapper.loadTilesFromResource(resource);
|
|
348
|
+
instanceWrapper.loadTilesFromResource(JSON.stringify(resource));
|
|
349
349
|
|
|
350
350
|
// Get a PseudoList and PseudoValue
|
|
351
351
|
const pseudoList = instanceWrapper.getValuesAtPath('basic_info.name');
|
|
@@ -433,13 +433,13 @@ describe('NapiResourceInstanceWrapper methods', () => {
|
|
|
433
433
|
|
|
434
434
|
it('has setTileDataForNode method', () => {
|
|
435
435
|
const wrapper = new NapiResourceInstanceWrapper(graphId);
|
|
436
|
-
wrapper.loadTilesFromResource(resource);
|
|
436
|
+
wrapper.loadTilesFromResource(JSON.stringify(resource));
|
|
437
437
|
assert.equal(typeof wrapper.setTileDataForNode, 'function');
|
|
438
438
|
});
|
|
439
439
|
|
|
440
440
|
it('setTileDataForNode mutates tile data', () => {
|
|
441
441
|
const wrapper = new NapiResourceInstanceWrapper(graphId);
|
|
442
|
-
wrapper.loadTilesFromResource(resource);
|
|
442
|
+
wrapper.loadTilesFromResource(JSON.stringify(resource));
|
|
443
443
|
|
|
444
444
|
const tileIds = wrapper.getAllTileIds();
|
|
445
445
|
assert.ok(tileIds.length > 0, 'should have tiles');
|
|
@@ -459,13 +459,13 @@ describe('NapiResourceInstanceWrapper methods', () => {
|
|
|
459
459
|
assert.equal(typeof wrapper.tilesLoaded, 'function');
|
|
460
460
|
assert.equal(wrapper.tilesLoaded(), false);
|
|
461
461
|
|
|
462
|
-
wrapper.loadTilesFromResource(resource);
|
|
462
|
+
wrapper.loadTilesFromResource(JSON.stringify(resource));
|
|
463
463
|
assert.equal(wrapper.tilesLoaded(), true);
|
|
464
464
|
});
|
|
465
465
|
|
|
466
466
|
it('has toJson method', () => {
|
|
467
467
|
const wrapper = new NapiResourceInstanceWrapper(graphId);
|
|
468
|
-
wrapper.loadTilesFromResource(resource);
|
|
468
|
+
wrapper.loadTilesFromResource(JSON.stringify(resource));
|
|
469
469
|
assert.equal(typeof wrapper.toJson, 'function');
|
|
470
470
|
// toJson requires populate() first; just verify the method exists
|
|
471
471
|
// and that calling it without populate gives a meaningful error
|
|
@@ -481,7 +481,7 @@ describe('NapiResourceInstanceWrapper methods', () => {
|
|
|
481
481
|
|
|
482
482
|
it('exportTilesJson returns valid JSON array of tiles', () => {
|
|
483
483
|
const wrapper = new NapiResourceInstanceWrapper(graphId);
|
|
484
|
-
wrapper.loadTilesFromResource(resource);
|
|
484
|
+
wrapper.loadTilesFromResource(JSON.stringify(resource));
|
|
485
485
|
|
|
486
486
|
const json = wrapper.exportTilesJson();
|
|
487
487
|
assert.equal(typeof json, 'string');
|
|
@@ -499,7 +499,7 @@ describe('NapiResourceInstanceWrapper methods', () => {
|
|
|
499
499
|
|
|
500
500
|
it('exportTilesJson reflects setTileDataForNode mutations', () => {
|
|
501
501
|
const wrapper = new NapiResourceInstanceWrapper(graphId);
|
|
502
|
-
wrapper.loadTilesFromResource(resource);
|
|
502
|
+
wrapper.loadTilesFromResource(JSON.stringify(resource));
|
|
503
503
|
|
|
504
504
|
const tileIds = wrapper.getAllTileIds();
|
|
505
505
|
const tileId = tileIds[0];
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/index.d.ts
CHANGED
|
@@ -40,6 +40,10 @@ export declare function extensionResolveMarkers(datatype: string, tileData: any,
|
|
|
40
40
|
export declare function hasExtensionHandler(datatype: string): boolean
|
|
41
41
|
/** List all registered extension handler datatypes. */
|
|
42
42
|
export declare function getRegisteredExtensionHandlers(): Array<string>
|
|
43
|
+
/** Parse SKOS RDF/XML and return all collections as a JSON array. */
|
|
44
|
+
export declare function parseSkosXml(xmlContent: string, baseUri: string): any
|
|
45
|
+
/** Parse SKOS RDF/XML and return a single collection (the first one found). */
|
|
46
|
+
export declare function parseSkosXmlToCollection(xmlContent: string, baseUri: string): any
|
|
43
47
|
/**
|
|
44
48
|
* Import a prebuild/pkg directory: register graphs, load SKOS collections,
|
|
45
49
|
* and load ontology configs.
|
|
@@ -66,6 +70,33 @@ export declare class NapiNodeConfigManager {
|
|
|
66
70
|
/** Build node configs from a NapiStaticGraph. */
|
|
67
71
|
buildFromGraph(graph: NapiStaticGraph): void
|
|
68
72
|
}
|
|
73
|
+
export declare class NapiTileData {
|
|
74
|
+
has(key: string): boolean
|
|
75
|
+
get(key: string): any
|
|
76
|
+
set(key: string, value: any): void
|
|
77
|
+
delete(key: string): boolean
|
|
78
|
+
keys(): Array<string>
|
|
79
|
+
}
|
|
80
|
+
export declare class NapiStaticTile {
|
|
81
|
+
constructor(nodegroupId: string, tileid?: string | undefined | null, sortorder?: number | undefined | null, resourceinstanceId?: string | undefined | null, parenttileId?: string | undefined | null)
|
|
82
|
+
get data(): NapiTileData
|
|
83
|
+
/**
|
|
84
|
+
* Setter is a no-op — data is always accessed via the NapiTileData getter.
|
|
85
|
+
* Exists to prevent TypeError in strict mode when JS does
|
|
86
|
+
* `tile.data = tile.data || new Map()`.
|
|
87
|
+
*/
|
|
88
|
+
set data(value: any)
|
|
89
|
+
get tileid(): string | null
|
|
90
|
+
set tileid(value?: string | undefined | null)
|
|
91
|
+
get nodegroupId(): string
|
|
92
|
+
get sortorder(): number | null
|
|
93
|
+
get resourceinstanceId(): string
|
|
94
|
+
get parenttileId(): string | null
|
|
95
|
+
set parenttileId(value?: string | undefined | null)
|
|
96
|
+
get provisionaledits(): any
|
|
97
|
+
/** Generate a tile ID if not already set. */
|
|
98
|
+
ensureId(): string
|
|
99
|
+
}
|
|
69
100
|
export declare class NapiPseudoValue {
|
|
70
101
|
get node(): any
|
|
71
102
|
get nodeId(): string | null
|
|
@@ -96,6 +127,12 @@ export declare class NapiPseudoValue {
|
|
|
96
127
|
toSnapshot(): any
|
|
97
128
|
/** Clear tile data */
|
|
98
129
|
clear(): void
|
|
130
|
+
get tile(): NapiStaticTile | null
|
|
131
|
+
set tile(tile?: NapiStaticTile | undefined | null)
|
|
132
|
+
/** Get the inner PseudoValueCore wrapped as NapiPseudoValue. */
|
|
133
|
+
get inner(): NapiPseudoValue | null
|
|
134
|
+
/** Returns null — value is managed JS-side via _cachedValue. */
|
|
135
|
+
get value(): any
|
|
99
136
|
}
|
|
100
137
|
export declare class NapiPseudoList {
|
|
101
138
|
get nodeAlias(): string
|
|
@@ -128,10 +165,15 @@ export declare class NapiValuesFromNodegroupResult {
|
|
|
128
165
|
export declare class NapiResourceInstanceWrapper {
|
|
129
166
|
/** Create a wrapper for a given graph (must be registered). */
|
|
130
167
|
constructor(graphId: string)
|
|
131
|
-
/** Load tiles from a JSON
|
|
132
|
-
loadTiles(
|
|
133
|
-
/** Load tiles directly from a StaticResource JSON. */
|
|
134
|
-
loadTilesFromResource(
|
|
168
|
+
/** Load tiles from a JSON string (single-pass deserialization). */
|
|
169
|
+
loadTiles(tilesJson: string): void
|
|
170
|
+
/** Load tiles directly from a StaticResource JSON string (single-pass deserialization). */
|
|
171
|
+
loadTilesFromResource(resourceJson: string): void
|
|
172
|
+
/**
|
|
173
|
+
* Load tiles directly from a NapiStaticResourceRegistry by resource ID.
|
|
174
|
+
* This avoids the JS round-trip of serializing tiles to JS and back.
|
|
175
|
+
*/
|
|
176
|
+
loadFromRegistry(resourceId: string, registry: NapiStaticResourceRegistry): boolean
|
|
135
177
|
/** Append tiles incrementally (for lazy loading). */
|
|
136
178
|
appendTiles(tilesJs: any): void
|
|
137
179
|
getTileCount(): number
|
package/index.js
CHANGED
|
@@ -310,10 +310,12 @@ if (!nativeBinding) {
|
|
|
310
310
|
throw new Error(`Failed to load native binding`)
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
const { NapiRdmCache, NapiNodeConfigManager, NapiPseudoValue, NapiPseudoList, NapiPopulateResult, NapiEnsureNodegroupResult, NapiValuesFromNodegroupResult, NapiResourceInstanceWrapper, NapiResourceModelWrapper, NapiPrebuildExporter, NapiStaticGraph, NapiStaticResourceRegistry, buildGraphFromCsvs, buildBusinessDataFromCsv, extensionCoerce, extensionRenderDisplay, extensionResolveMarkers, hasExtensionHandler, getRegisteredExtensionHandlers, importPrebuild } = nativeBinding
|
|
313
|
+
const { NapiRdmCache, NapiNodeConfigManager, NapiTileData, NapiStaticTile, NapiPseudoValue, NapiPseudoList, NapiPopulateResult, NapiEnsureNodegroupResult, NapiValuesFromNodegroupResult, NapiResourceInstanceWrapper, NapiResourceModelWrapper, NapiPrebuildExporter, NapiStaticGraph, NapiStaticResourceRegistry, buildGraphFromCsvs, buildBusinessDataFromCsv, extensionCoerce, extensionRenderDisplay, extensionResolveMarkers, hasExtensionHandler, getRegisteredExtensionHandlers, parseSkosXml, parseSkosXmlToCollection, importPrebuild } = nativeBinding
|
|
314
314
|
|
|
315
315
|
module.exports.NapiRdmCache = NapiRdmCache
|
|
316
316
|
module.exports.NapiNodeConfigManager = NapiNodeConfigManager
|
|
317
|
+
module.exports.NapiTileData = NapiTileData
|
|
318
|
+
module.exports.NapiStaticTile = NapiStaticTile
|
|
317
319
|
module.exports.NapiPseudoValue = NapiPseudoValue
|
|
318
320
|
module.exports.NapiPseudoList = NapiPseudoList
|
|
319
321
|
module.exports.NapiPopulateResult = NapiPopulateResult
|
|
@@ -331,4 +333,6 @@ module.exports.extensionRenderDisplay = extensionRenderDisplay
|
|
|
331
333
|
module.exports.extensionResolveMarkers = extensionResolveMarkers
|
|
332
334
|
module.exports.hasExtensionHandler = hasExtensionHandler
|
|
333
335
|
module.exports.getRegisteredExtensionHandlers = getRegisteredExtensionHandlers
|
|
336
|
+
module.exports.parseSkosXml = parseSkosXml
|
|
337
|
+
module.exports.parseSkosXmlToCollection = parseSkosXmlToCollection
|
|
334
338
|
module.exports.importPrebuild = importPrebuild
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alizarin/napi",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.93",
|
|
4
4
|
"license": "AGPL-3.0-or-later",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"@napi-rs/cli": "^2.18.0"
|
|
31
31
|
},
|
|
32
32
|
"optionalDependencies": {
|
|
33
|
-
"@alizarin/napi-win32-x64-msvc": "2.0.0-alpha.
|
|
34
|
-
"@alizarin/napi-darwin-x64": "2.0.0-alpha.
|
|
35
|
-
"@alizarin/napi-linux-x64-gnu": "2.0.0-alpha.
|
|
33
|
+
"@alizarin/napi-win32-x64-msvc": "2.0.0-alpha.93",
|
|
34
|
+
"@alizarin/napi-darwin-x64": "2.0.0-alpha.93",
|
|
35
|
+
"@alizarin/napi-linux-x64-gnu": "2.0.0-alpha.93"
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/// the TypeScript ViewModel layer (ResourceInstanceWrapper / PseudoValue / PseudoList)
|
|
5
5
|
/// can work with either backend.
|
|
6
6
|
use std::collections::HashMap;
|
|
7
|
-
use std::sync::Arc;
|
|
7
|
+
use std::sync::{Arc, Mutex};
|
|
8
8
|
|
|
9
9
|
use napi::bindgen_prelude::*;
|
|
10
10
|
use napi_derive::napi;
|
|
@@ -118,6 +118,181 @@ impl NapiNodeConfigManager {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
// =============================================================================
|
|
122
|
+
// NapiTileData — Map-like interface over HashMap<String, Value>
|
|
123
|
+
// =============================================================================
|
|
124
|
+
|
|
125
|
+
#[napi]
|
|
126
|
+
pub struct NapiTileData {
|
|
127
|
+
entries: Arc<Mutex<HashMap<String, serde_json::Value>>>,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#[napi]
|
|
131
|
+
impl NapiTileData {
|
|
132
|
+
#[napi]
|
|
133
|
+
pub fn has(&self, key: String) -> bool {
|
|
134
|
+
self.entries.lock().unwrap().contains_key(&key)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
#[napi]
|
|
138
|
+
pub fn get(&self, key: String) -> serde_json::Value {
|
|
139
|
+
self.entries
|
|
140
|
+
.lock()
|
|
141
|
+
.unwrap()
|
|
142
|
+
.get(&key)
|
|
143
|
+
.cloned()
|
|
144
|
+
.unwrap_or(serde_json::Value::Null)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#[napi]
|
|
148
|
+
pub fn set(&mut self, key: String, value: serde_json::Value) {
|
|
149
|
+
self.entries.lock().unwrap().insert(key, value);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
#[napi]
|
|
153
|
+
pub fn delete(&mut self, key: String) -> bool {
|
|
154
|
+
self.entries.lock().unwrap().remove(&key).is_some()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
#[napi]
|
|
158
|
+
pub fn keys(&self) -> Vec<String> {
|
|
159
|
+
self.entries.lock().unwrap().keys().cloned().collect()
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// =============================================================================
|
|
164
|
+
// NapiStaticTile — Rust-owned tile with Map-like .data access
|
|
165
|
+
// =============================================================================
|
|
166
|
+
|
|
167
|
+
#[napi]
|
|
168
|
+
pub struct NapiStaticTile {
|
|
169
|
+
tileid: Option<String>,
|
|
170
|
+
nodegroup_id: String,
|
|
171
|
+
sortorder: Option<i32>,
|
|
172
|
+
resourceinstance_id: String,
|
|
173
|
+
parenttile_id: Option<String>,
|
|
174
|
+
provisionaledits: Option<Vec<serde_json::Value>>,
|
|
175
|
+
data_store: Arc<Mutex<HashMap<String, serde_json::Value>>>,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
#[napi]
|
|
179
|
+
impl NapiStaticTile {
|
|
180
|
+
#[napi(constructor)]
|
|
181
|
+
pub fn new(
|
|
182
|
+
nodegroup_id: String,
|
|
183
|
+
tileid: Option<String>,
|
|
184
|
+
sortorder: Option<i32>,
|
|
185
|
+
resourceinstance_id: Option<String>,
|
|
186
|
+
parenttile_id: Option<String>,
|
|
187
|
+
) -> Self {
|
|
188
|
+
NapiStaticTile {
|
|
189
|
+
tileid,
|
|
190
|
+
nodegroup_id,
|
|
191
|
+
sortorder,
|
|
192
|
+
resourceinstance_id: resourceinstance_id.unwrap_or_default(),
|
|
193
|
+
parenttile_id,
|
|
194
|
+
provisionaledits: None,
|
|
195
|
+
data_store: Arc::new(Mutex::new(HashMap::new())),
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
#[napi(getter)]
|
|
200
|
+
pub fn data(&self) -> NapiTileData {
|
|
201
|
+
NapiTileData {
|
|
202
|
+
entries: self.data_store.clone(),
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/// Setter is a no-op — data is always accessed via the NapiTileData getter.
|
|
207
|
+
/// Exists to prevent TypeError in strict mode when JS does
|
|
208
|
+
/// `tile.data = tile.data || new Map()`.
|
|
209
|
+
#[napi(setter)]
|
|
210
|
+
pub fn set_data(&mut self, _value: serde_json::Value) {
|
|
211
|
+
// No-op: mutations go through NapiTileData.set/delete
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
#[napi(getter)]
|
|
215
|
+
pub fn tileid(&self) -> Option<String> {
|
|
216
|
+
self.tileid.clone()
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
#[napi(setter)]
|
|
220
|
+
pub fn set_tileid(&mut self, value: Option<String>) {
|
|
221
|
+
self.tileid = value;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
#[napi(getter)]
|
|
225
|
+
pub fn nodegroup_id(&self) -> String {
|
|
226
|
+
self.nodegroup_id.clone()
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
#[napi(getter)]
|
|
230
|
+
pub fn sortorder(&self) -> Option<i32> {
|
|
231
|
+
self.sortorder
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
#[napi(getter)]
|
|
235
|
+
pub fn resourceinstance_id(&self) -> String {
|
|
236
|
+
self.resourceinstance_id.clone()
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
#[napi(getter)]
|
|
240
|
+
pub fn parenttile_id(&self) -> Option<String> {
|
|
241
|
+
self.parenttile_id.clone()
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#[napi(setter)]
|
|
245
|
+
pub fn set_parenttile_id(&mut self, value: Option<String>) {
|
|
246
|
+
self.parenttile_id = value;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
#[napi(getter)]
|
|
250
|
+
pub fn provisionaledits(&self) -> serde_json::Value {
|
|
251
|
+
match &self.provisionaledits {
|
|
252
|
+
Some(edits) => serde_json::to_value(edits).unwrap_or(serde_json::Value::Null),
|
|
253
|
+
None => serde_json::Value::Null,
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/// Generate a tile ID if not already set.
|
|
258
|
+
#[napi(js_name = "ensureId")]
|
|
259
|
+
pub fn ensure_id(&mut self) -> String {
|
|
260
|
+
if self.tileid.is_none() {
|
|
261
|
+
self.tileid = Some(uuid::Uuid::new_v4().to_string());
|
|
262
|
+
}
|
|
263
|
+
self.tileid.clone().unwrap()
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
impl NapiStaticTile {
|
|
268
|
+
/// Convert to core StaticTile for storage in PseudoValueCore.
|
|
269
|
+
pub(crate) fn to_static_tile(&self) -> StaticTile {
|
|
270
|
+
let data = self.data_store.lock().unwrap().clone();
|
|
271
|
+
StaticTile {
|
|
272
|
+
tileid: self.tileid.clone(),
|
|
273
|
+
nodegroup_id: self.nodegroup_id.clone(),
|
|
274
|
+
sortorder: self.sortorder,
|
|
275
|
+
resourceinstance_id: self.resourceinstance_id.clone(),
|
|
276
|
+
parenttile_id: self.parenttile_id.clone(),
|
|
277
|
+
provisionaledits: self.provisionaledits.clone(),
|
|
278
|
+
data,
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/// Create from a core StaticTile.
|
|
283
|
+
pub(crate) fn from_static_tile(tile: &StaticTile) -> Self {
|
|
284
|
+
NapiStaticTile {
|
|
285
|
+
tileid: tile.tileid.clone(),
|
|
286
|
+
nodegroup_id: tile.nodegroup_id.clone(),
|
|
287
|
+
sortorder: tile.sortorder,
|
|
288
|
+
resourceinstance_id: tile.resourceinstance_id.clone(),
|
|
289
|
+
parenttile_id: tile.parenttile_id.clone(),
|
|
290
|
+
provisionaledits: tile.provisionaledits.clone(),
|
|
291
|
+
data_store: Arc::new(Mutex::new(tile.data.clone())),
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
121
296
|
// =============================================================================
|
|
122
297
|
// NapiPseudoValue
|
|
123
298
|
// =============================================================================
|
|
@@ -269,15 +444,17 @@ impl NapiPseudoValue {
|
|
|
269
444
|
pub fn to_snapshot(&self) -> serde_json::Value {
|
|
270
445
|
serde_json::json!({
|
|
271
446
|
"nodeId": self.inner.node.nodeid,
|
|
447
|
+
"name": &self.inner.node.name,
|
|
272
448
|
"alias": self.inner.node.alias,
|
|
273
449
|
"datatype": &self.inner.node.datatype,
|
|
274
450
|
"nodegroupId": self.inner.node.nodegroup_id,
|
|
451
|
+
"sortorder": self.inner.node.sortorder,
|
|
452
|
+
"isOuter": self.inner.is_outer(),
|
|
453
|
+
"isInner": self.inner.is_inner,
|
|
275
454
|
"isCollector": self.inner.is_collector,
|
|
455
|
+
"accessed": false,
|
|
276
456
|
"independent": self.inner.independent,
|
|
277
|
-
"
|
|
278
|
-
"isrequired": self.inner.node.isrequired,
|
|
279
|
-
"issearchable": self.inner.node.issearchable,
|
|
280
|
-
"hascustomalias": self.inner.node.hascustomalias,
|
|
457
|
+
"hasTile": self.inner.tile.is_some(),
|
|
281
458
|
"tileId": self.inner.tile.as_ref().and_then(|t| t.tileid.clone()),
|
|
282
459
|
"tileData": &self.inner.tile_data,
|
|
283
460
|
"valueLoaded": self.inner.tile.is_some(),
|
|
@@ -290,6 +467,45 @@ impl NapiPseudoValue {
|
|
|
290
467
|
pub fn clear(&mut self) {
|
|
291
468
|
self.inner.tile_data = None;
|
|
292
469
|
}
|
|
470
|
+
|
|
471
|
+
// -- Tile getter/setter (NapiStaticTile, Rust-owned) --
|
|
472
|
+
|
|
473
|
+
#[napi(getter, js_name = "tile")]
|
|
474
|
+
pub fn get_tile(&self) -> Option<NapiStaticTile> {
|
|
475
|
+
self.inner
|
|
476
|
+
.tile
|
|
477
|
+
.as_ref()
|
|
478
|
+
.map(|t| NapiStaticTile::from_static_tile(t.as_ref()))
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
#[napi(setter, js_name = "tile")]
|
|
482
|
+
pub fn set_tile(&mut self, tile: Option<&NapiStaticTile>) {
|
|
483
|
+
match tile {
|
|
484
|
+
Some(t) => {
|
|
485
|
+
self.inner.tile = Some(Arc::new(t.to_static_tile()));
|
|
486
|
+
}
|
|
487
|
+
None => {
|
|
488
|
+
self.inner.tile = None;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// -- Inner (outer/inner pattern) --
|
|
494
|
+
|
|
495
|
+
/// Get the inner PseudoValueCore wrapped as NapiPseudoValue.
|
|
496
|
+
#[napi(getter)]
|
|
497
|
+
pub fn inner(&self) -> Option<NapiPseudoValue> {
|
|
498
|
+
self.inner
|
|
499
|
+
.inner
|
|
500
|
+
.as_ref()
|
|
501
|
+
.map(|i| NapiPseudoValue { inner: *i.clone() })
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/// Returns null — value is managed JS-side via _cachedValue.
|
|
505
|
+
#[napi(getter)]
|
|
506
|
+
pub fn value(&self) -> serde_json::Value {
|
|
507
|
+
serde_json::Value::Null
|
|
508
|
+
}
|
|
293
509
|
}
|
|
294
510
|
|
|
295
511
|
// =============================================================================
|
|
@@ -530,19 +746,19 @@ impl NapiResourceInstanceWrapper {
|
|
|
530
746
|
// Tile loading
|
|
531
747
|
// =========================================================================
|
|
532
748
|
|
|
533
|
-
/// Load tiles from a JSON
|
|
749
|
+
/// Load tiles from a JSON string (single-pass deserialization).
|
|
534
750
|
#[napi]
|
|
535
|
-
pub fn load_tiles(&mut self,
|
|
536
|
-
let tiles: Vec<StaticTile> = serde_json::
|
|
751
|
+
pub fn load_tiles(&mut self, tiles_json: String) -> Result<()> {
|
|
752
|
+
let tiles: Vec<StaticTile> = serde_json::from_str(&tiles_json)
|
|
537
753
|
.map_err(|e| napi::Error::from_reason(format!("Invalid tiles JSON: {e}")))?;
|
|
538
754
|
self.inner.load_tiles(tiles);
|
|
539
755
|
Ok(())
|
|
540
756
|
}
|
|
541
757
|
|
|
542
|
-
/// Load tiles directly from a StaticResource JSON.
|
|
758
|
+
/// Load tiles directly from a StaticResource JSON string (single-pass deserialization).
|
|
543
759
|
#[napi]
|
|
544
|
-
pub fn load_tiles_from_resource(&mut self,
|
|
545
|
-
let resource: StaticResource = serde_json::
|
|
760
|
+
pub fn load_tiles_from_resource(&mut self, resource_json: String) -> Result<()> {
|
|
761
|
+
let resource: StaticResource = serde_json::from_str(&resource_json)
|
|
546
762
|
.map_err(|e| napi::Error::from_reason(format!("Invalid resource JSON: {e}")))?;
|
|
547
763
|
|
|
548
764
|
self.inner.resource_instance = Some(resource.resourceinstance.clone());
|
package/src/lib.rs
CHANGED
|
@@ -529,6 +529,35 @@ pub fn get_registered_extension_handlers() -> Vec<String> {
|
|
|
529
529
|
.collect()
|
|
530
530
|
}
|
|
531
531
|
|
|
532
|
+
// ============================================================================
|
|
533
|
+
// SKOS parsing
|
|
534
|
+
// ============================================================================
|
|
535
|
+
|
|
536
|
+
/// Parse SKOS RDF/XML and return all collections as a JSON array.
|
|
537
|
+
#[napi(js_name = "parseSkosXml")]
|
|
538
|
+
pub fn parse_skos_xml(xml_content: String, base_uri: String) -> Result<serde_json::Value> {
|
|
539
|
+
let collections = alizarin_core::skos::parse_skos_to_collections(&xml_content, &base_uri)
|
|
540
|
+
.map_err(napi::Error::from_reason)?;
|
|
541
|
+
serde_json::to_value(&collections).map_err(|e| napi::Error::from_reason(e.to_string()))
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/// Parse SKOS RDF/XML and return a single collection (the first one found).
|
|
545
|
+
#[napi(js_name = "parseSkosXmlToCollection")]
|
|
546
|
+
pub fn parse_skos_xml_to_collection(
|
|
547
|
+
xml_content: String,
|
|
548
|
+
base_uri: String,
|
|
549
|
+
) -> Result<serde_json::Value> {
|
|
550
|
+
let mut collections = alizarin_core::skos::parse_skos_to_collections(&xml_content, &base_uri)
|
|
551
|
+
.map_err(napi::Error::from_reason)?;
|
|
552
|
+
if collections.is_empty() {
|
|
553
|
+
return Err(napi::Error::from_reason(
|
|
554
|
+
"No SKOS ConceptScheme found in XML".to_string(),
|
|
555
|
+
));
|
|
556
|
+
}
|
|
557
|
+
let collection = collections.remove(0);
|
|
558
|
+
serde_json::to_value(&collection).map_err(|e| napi::Error::from_reason(e.to_string()))
|
|
559
|
+
}
|
|
560
|
+
|
|
532
561
|
// ============================================================================
|
|
533
562
|
// Prebuild import (high-level convenience)
|
|
534
563
|
// ============================================================================
|