Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ A joint effort on fundamental features (where differentiation isn't possible any
improves quality and assures interoperability.

The reference implementation addresses the following aspects:
- Check data format and constraints according to the [CascAra meta-model](https://cascaRA.gfse.org/results/Latest%20Metamodel/)
- Check data format and constraints according to the [CASCaRA meta-model](https://product-information-graph.org/doc/metamodel/latest/)
to assure data quality.
- Persistently store and retrieve PIG data using the standardized API (to be defined).
- View and edit PIG data in a web-browser.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "CASCaRA_PIG-App",
"name": "CASCaRA-App",
"version": "0.1.0",
"private": true,
"scripts": {
Expand Down
Binary file removed public/assets/jsonld/jsonld.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion public/assets/xslt/ReqIF-to-PIG.sef.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<base href="./"> <!-- relative paths are always relative to index.prod.html -->
<base href="./" /> <!-- relative paths are always relative to index.prod.html -->
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700|Roboto:400,700&display=swap" rel="stylesheet" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
Expand Down
34 changes: 21 additions & 13 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
<template>
<v-app>
<Navigation msg="CASCaRA"/>
<Navigation :msg="DEF.appName" />

<v-main>
<v-container fluid>
<router-view></router-view>
<router-view></router-view>
</v-container>
</v-main>
</v-app>
</template>

<script lang="ts">
import { Vue } from 'vue-class-component';
export default class App extends Vue {}
import { Vue, Options } from 'vue-class-component';
import { DEF } from '@/common-code/lib/definitions';

@Options({
computed: {
DEF() {
return DEF;
}
}
})
export default class App extends Vue { }
</script>

<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
#app {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
10 changes: 5 additions & 5 deletions src/build-info.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Auto-generated by scripts/generate-build-info.js - DO NOT EDIT
// Generated at: 2026-02-23T16:39:18.651Z
// Generated at: 2026-02-27T14:13:52.124Z

export const BUILD_INFO = {
// from package.json:
appName: 'CASCaRA_PIG-App',
appName: 'CASCaRA-App',
appVersion: '0.1.0',
// from Git:
buildTime: '2026-02-23T16:39:18.651Z',
gitCommit: '6f3c2e4',
gitBranch: '52-installable-with-relative-links',
buildTime: '2026-02-27T14:13:52.124Z',
gitCommit: '46b49fd',
gitBranch: '#25-Improve-HTML-rendering',
gitDirty: false
};
3 changes: 3 additions & 0 deletions src/common-code/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Common Code

This folder contains code common to all deployment packages, namely for the browser and the server.
174 changes: 174 additions & 0 deletions src/common-code/import/jsonld/import-jsonld.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*!
* Cross-environment JSON-LD importer.
* Copyright 2025 GfSE (https://gfse.org)
* License and terms of use: Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
*/
/**
* JSON-LD Importer - Static class for importing PIG JSON-LD documents
*
* Cross-environment JSON-LD importer:
* - Accepts a Node file path, an http(s) URL string or a browser File/Blob.
* - Extracts elements from '@graph' (or 'graph'), converts JSON-LD keys to internal keys
* and instantiates matching PIG class instances where possible.
*
* Authors: oskar.dungern@gfse.org
*
* Design Decisions:
* - Static class design for consistency with ReqIFImporter and XmlImporter
* - Direct JSON-LD processing without transformation
* - Validation through APackage.setJSONLD() method
*
* Usage:
* - Node: await JsonldImporter.import('C:/path/to/file.jsonld')
* - URL: await JsonldImporter.import('https://example/.../doc.jsonld')
* - Browser: await JsonldImporter.import(fileInput.files[0])
*/

import { IRsp, rspOK, Rsp, Msg } from '../../lib/messages';
import { LOG } from '../../lib/helpers';
import { PIN } from '../../lib/platform-independence';
import { APackage, TPigItem } from '../../schema/pig/ts/pig-metaclasses';
import { SCH_LD } from '../../schema/pig/jsonld/pig-schemata-jsonld';

/**
* JSON-LD document structure
*/
interface JsonLdDocument {
'@context'?: unknown;
'@graph'?: unknown[];
'@id'?: string;
'@type'?: string | string[];
[key: string]: unknown;
}

/**
* JSON-LD Importer
* Static class for importing and parsing PIG JSON-LD documents
*/
export class JsonldImporter {
/**
* Import JSON-LD document and instantiate PIG items
*
* @param source - File path (Node.js), URL, or File/Blob object (Browser)
* @returns IRsp containing array of TPigItem (first item is APackage, rest are graph items)
*
* @example
* // Node.js
* const result = await JsonldImporter.import('./package.jsonld');
*
* @example
* // Browser
* const file = fileInput.files[0];
* const result = await JsonldImporter.import(file);
*
* @example
* // URL
* const result = await JsonldImporter.import('https://example.org/data.jsonld');
*/
static async import(source: string | File | Blob): Promise<IRsp> {
// Read file content
const rsp = await PIN.readFileAsText(source);
if (!rsp.ok) {
return rsp;
}

const text = rsp.response as string;

// Parse JSON document
let doc: JsonLdDocument;
try {
doc = JSON.parse(text) as JsonLdDocument;
} catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : String(err);
return Msg.create(690, 'JSON-LD', errorMessage);
}

// Validate JSON-LD document structure
const validationResult = await this.validateJsonLdDocument(doc);
if (!validationResult.ok) {
return validationResult;
}

// Instantiate APackage and load the document
const aPackage = new APackage().setJSONLD(doc);

// Check if package was successfully created
if (!aPackage.status().ok) {
return aPackage.status();
}

// Get all items (package + graph items)
const allItems = aPackage.getItems();

// Calculate import statistics
const expectedCount = doc['@graph']?.length || 0;
const actualCount = allItems.length - 1; // -1 for package itself

// Build result response
let result: IRsp;
if (actualCount === expectedCount) {
LOG.info(
`JsonldImporter: successfully imported package with all ${actualCount} items`
);
result = Rsp.create(0, allItems, 'json', 'JSON-LD', actualCount, expectedCount);
} else {
// Log details about erroneous items
const errorDetails = this.buildErrorReport(allItems);
LOG.warn(
`JsonldImporter: imported ${actualCount} of ${expectedCount} items${errorDetails}`
);

result = Rsp.create(691, allItems, 'json', 'JSON-LD', actualCount, expectedCount);
}

return result as IRsp<TPigItem[]>;
}

/**
* Validate JSON-LD document structure
*
* Checks for:
* - Valid @context
* - Valid @graph structure
* - Schema compliance
*
* @param doc - Parsed JSON-LD document
* @returns IRsp indicating success or error
* @private
*/
private static async validateJsonLdDocument(doc: JsonLdDocument): Promise<IRsp> {
// Validate entire JSON-LD document structure using schema
const isValidPackage = await SCH_LD.validatePackageLD(doc);

if (!isValidPackage) {
const errors = await SCH_LD.getValidatePackageLDErrors();
LOG.error('JSON-LD package validation failed:', errors);
return Msg.create(697, 'JSON-LD', errors);
}

return rspOK;
}

/**
* Build detailed error report for failed items
*
* @param allItems - All items including package
* @returns Formatted error report string
* @private
*/
private static buildErrorReport(allItems: TPigItem[]): string {
let errorReport = '\nErroneous items:';

for (let i = 1; i < allItems.length; i++) {
const status = allItems[i].status();
if (!status.ok) {
errorReport += `\n- graph[${i}]: (${status.status}) ${status.statusText}`;
}
}

return errorReport;
}
}

// Export convenience function for backward compatibility
// export const importJSONLD = JsonldImporter.import.bind(JsonldImporter);
Loading