mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 14:23:53 +00:00
check-whitespace: normalize javascript files
This commit is contained in:
@@ -297,6 +297,8 @@ PATTERNS = (
|
|||||||
"*/CMakeLists.txt",
|
"*/CMakeLists.txt",
|
||||||
"*.yml",
|
"*.yml",
|
||||||
"*.yaml",
|
"*.yaml",
|
||||||
|
"*.ts",
|
||||||
|
"*.js",
|
||||||
"*.bat",
|
"*.bat",
|
||||||
"*.cmd",
|
"*.cmd",
|
||||||
"*.sh",
|
"*.sh",
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ function toggleClientList() {
|
|||||||
const clientNumbers = $("<div>")
|
const clientNumbers = $("<div>")
|
||||||
.addClass("client-detail")
|
.addClass("client-detail")
|
||||||
.text(
|
.text(
|
||||||
`${allDrawings[client.ifc_file].drawings.length} Drawing(s),
|
`${allDrawings[client.ifc_file].drawings.length} Drawing(s),
|
||||||
${allDrawings[client.ifc_file].sheets.length} Sheet(s)`
|
${allDrawings[client.ifc_file].sheets.length} Sheet(s)`
|
||||||
);
|
);
|
||||||
clientDetailsDiv.append(clientNumbers);
|
clientDetailsDiv.append(clientNumbers);
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ function toggleClientList() {
|
|||||||
const clientNumbers = $("<div>")
|
const clientNumbers = $("<div>")
|
||||||
.addClass("client-detail")
|
.addClass("client-detail")
|
||||||
.text(
|
.text(
|
||||||
`${allDrawings[client.ifc_file].drawings.length} Drawing(s),
|
`${allDrawings[client.ifc_file].drawings.length} Drawing(s),
|
||||||
${allDrawings[client.ifc_file].sheets.length} Sheet(s)`
|
${allDrawings[client.ifc_file].sheets.length} Sheet(s)`
|
||||||
);
|
);
|
||||||
clientDetailsDiv.append(clientNumbers);
|
clientDetailsDiv.append(clientNumbers);
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ function setupPage(workScheduleData){
|
|||||||
g.setTotalHeight("");
|
g.setTotalHeight("");
|
||||||
g.Draw();
|
g.Draw();
|
||||||
var values = document.getElementById("print_page_size").value.split(",")
|
var values = document.getElementById("print_page_size").value.split(",")
|
||||||
let css =
|
let css =
|
||||||
"@media print {\n @page {\n size: " + values[0] + "mm " + values[1] + "mm;\n }\n";
|
"@media print {\n @page {\n size: " + values[0] + "mm " + values[1] + "mm;\n }\n";
|
||||||
g.printChart(values[0], values[1], css);
|
g.printChart(values[0], values[1], css);
|
||||||
g.setTotalHeight(900);
|
g.setTotalHeight(900);
|
||||||
@@ -109,4 +109,4 @@ function setupPage(workScheduleData){
|
|||||||
let creation_date_string = document.createTextNode("Created: " + new Date(workScheduleData.CreationDate).toLocaleDateString());
|
let creation_date_string = document.createTextNode("Created: " + new Date(workScheduleData.CreationDate).toLocaleDateString());
|
||||||
creation_date.appendChild(creation_date_string);
|
creation_date.appendChild(creation_date_string);
|
||||||
document.getElementById("schedule-header").appendChild(creation_date);
|
document.getElementById("schedule-header").appendChild(creation_date);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -99,29 +99,29 @@ const PROVIDERS = {
|
|||||||
baseUrlPlaceholder: "https://openrouter.ai/api/v1",
|
baseUrlPlaceholder: "https://openrouter.ai/api/v1",
|
||||||
baseUrlDefault: "https://openrouter.ai/api/v1",
|
baseUrlDefault: "https://openrouter.ai/api/v1",
|
||||||
models: [
|
models: [
|
||||||
{
|
{
|
||||||
value: "openai/gpt-oss-20b",
|
value: "openai/gpt-oss-20b",
|
||||||
label: "gpt-oss-20b"
|
label: "gpt-oss-20b"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "openai/gpt-oss-120b",
|
value: "openai/gpt-oss-120b",
|
||||||
label: "gpt-oss-120b"
|
label: "gpt-oss-120b"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "mistralai/mistral-small-3.2-24b-instruct",
|
value: "mistralai/mistral-small-3.2-24b-instruct",
|
||||||
label: "mistral-small-3.2"
|
label: "mistral-small-3.2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "openai/gpt-4.1",
|
value: "openai/gpt-4.1",
|
||||||
label: "gpt-4.1"
|
label: "gpt-4.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "anthropic/claude-sonnet-4-5",
|
value: "anthropic/claude-sonnet-4-5",
|
||||||
label: "claude-sonnet-4-5"
|
label: "claude-sonnet-4-5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "google/gemini-2.5-pro-preview",
|
value: "google/gemini-2.5-pro-preview",
|
||||||
label: "gemini-2.5-pro"
|
label: "gemini-2.5-pro"
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ async function ensurePyodide() {
|
|||||||
await pyodide.loadPackage("numpy");
|
await pyodide.loadPackage("numpy");
|
||||||
await pyodide.loadPackage("shapely");
|
await pyodide.loadPackage("shapely");
|
||||||
await pyodide.loadPackage("typing-extensions");
|
await pyodide.loadPackage("typing-extensions");
|
||||||
|
|
||||||
const micropip = pyodide.pyimport("micropip");
|
const micropip = pyodide.pyimport("micropip");
|
||||||
micropip.install("python-dateutil")
|
micropip.install("python-dateutil")
|
||||||
|
|
||||||
const wheelUrl = "https://ifcopenshell.github.io/wasm-wheels/ifcopenshell-0.8.5-cp313-cp313-pyodide_2025_0_wasm32.whl";
|
const wheelUrl = "https://ifcopenshell.github.io/wasm-wheels/ifcopenshell-0.8.5-cp313-cp313-pyodide_2025_0_wasm32.whl";
|
||||||
|
|
||||||
await micropip.install(wheelUrl);
|
await micropip.install(wheelUrl);
|
||||||
@@ -98,4 +98,4 @@ self.onmessage = async (ev) => {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
fail(id, e);
|
fail(id, e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,4 +34,4 @@ export {
|
|||||||
Content as DialogContent,
|
Content as DialogContent,
|
||||||
Description as DialogDescription,
|
Description as DialogDescription,
|
||||||
Close as DialogClose,
|
Close as DialogClose,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -46,4 +46,4 @@ export {
|
|||||||
SubContent,
|
SubContent,
|
||||||
SubTrigger,
|
SubTrigger,
|
||||||
Trigger,
|
Trigger,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -51,4 +51,4 @@ export {
|
|||||||
RadioGroup as MenubarRadioGroup,
|
RadioGroup as MenubarRadioGroup,
|
||||||
Label as MenubarLabel,
|
Label as MenubarLabel,
|
||||||
GroupHeading as MenubarGroupHeading,
|
GroupHeading as MenubarGroupHeading,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default as Toaster } from "./sonner.svelte";
|
export { default as Toaster } from "./sonner.svelte";
|
||||||
|
|||||||
@@ -18,4 +18,4 @@ export {
|
|||||||
Trigger as TooltipTrigger,
|
Trigger as TooltipTrigger,
|
||||||
Provider as TooltipProvider,
|
Provider as TooltipProvider,
|
||||||
Portal as TooltipPortal,
|
Portal as TooltipPortal,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ wasm.init().then(async () => {
|
|||||||
export async function preloadAutocompletions() {
|
export async function preloadAutocompletions() {
|
||||||
try {
|
try {
|
||||||
const schemas = ["IFC2X3", "IFC4"]; // TODO: IFC4X3 is excluded for now because of an error
|
const schemas = ["IFC2X3", "IFC4"]; // TODO: IFC4X3 is excluded for now because of an error
|
||||||
|
|
||||||
// Entity classes
|
// Entity classes
|
||||||
const entitySets = await Promise.all(
|
const entitySets = await Promise.all(
|
||||||
schemas.map(schema => wasm.getAllEntityClasses(schema))
|
schemas.map(schema => wasm.getAllEntityClasses(schema))
|
||||||
@@ -60,7 +60,7 @@ export async function preloadAutocompletions() {
|
|||||||
allEntities.add(entity.toUpperCase());
|
allEntities.add(entity.toUpperCase());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data types
|
// Data types
|
||||||
const dataTypeSets = await Promise.all(
|
const dataTypeSets = await Promise.all(
|
||||||
schemas.map(schema => wasm.getAllDataTypes(schema))
|
schemas.map(schema => wasm.getAllDataTypes(schema))
|
||||||
@@ -71,20 +71,20 @@ export async function preloadAutocompletions() {
|
|||||||
allDataTypes.add(dataType);
|
allDataTypes.add(dataType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Material categories and Classification systems
|
// Material categories and Classification systems
|
||||||
const [materialCategories, classificationSystems] = await Promise.all([
|
const [materialCategories, classificationSystems] = await Promise.all([
|
||||||
wasm.getMaterialCategories(),
|
wasm.getMaterialCategories(),
|
||||||
wasm.getStandardClassificationSystems()
|
wasm.getStandardClassificationSystems()
|
||||||
]) as [string[], AutocompletionState["classificationSystems"]];
|
]) as [string[], AutocompletionState["classificationSystems"]];
|
||||||
|
|
||||||
// Cache autocompletions
|
// Cache autocompletions
|
||||||
Autocompletions.entityClasses = Array.from(allEntities).sort();
|
Autocompletions.entityClasses = Array.from(allEntities).sort();
|
||||||
Autocompletions.materialCategories = materialCategories;
|
Autocompletions.materialCategories = materialCategories;
|
||||||
Autocompletions.classificationSystems = classificationSystems;
|
Autocompletions.classificationSystems = classificationSystems;
|
||||||
Autocompletions.dataTypes = Array.from(allDataTypes).sort();
|
Autocompletions.dataTypes = Array.from(allDataTypes).sort();
|
||||||
Autocompletions.isLoaded = true;
|
Autocompletions.isLoaded = true;
|
||||||
|
|
||||||
console.log('Autocompletions preloaded');
|
console.log('Autocompletions preloaded');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to preload autocompletions:', error);
|
console.error('Failed to preload autocompletions:', error);
|
||||||
@@ -122,13 +122,13 @@ export function getDataTypes() {
|
|||||||
export async function loadIfc(file: File): Promise<IfcModel> {
|
export async function loadIfc(file: File): Promise<IfcModel> {
|
||||||
try {
|
try {
|
||||||
IFCModels.isLoading = true;
|
IFCModels.isLoading = true;
|
||||||
|
|
||||||
const arrayBuffer = await file.arrayBuffer();
|
const arrayBuffer = await file.arrayBuffer();
|
||||||
const uint8Array = new Uint8Array(arrayBuffer);
|
const uint8Array = new Uint8Array(arrayBuffer);
|
||||||
|
|
||||||
// Load IFC model
|
// Load IFC model
|
||||||
const ifcId = await wasm.loadIfc(Array.from(uint8Array)) as string;
|
const ifcId = await wasm.loadIfc(Array.from(uint8Array)) as string;
|
||||||
|
|
||||||
// Add to models list
|
// Add to models list
|
||||||
const model: IfcModel = {
|
const model: IfcModel = {
|
||||||
id: ifcId,
|
id: ifcId,
|
||||||
@@ -137,7 +137,7 @@ export async function loadIfc(file: File): Promise<IfcModel> {
|
|||||||
loadedAt: new Date()
|
loadedAt: new Date()
|
||||||
};
|
};
|
||||||
IFCModels.models = [...IFCModels.models, model];
|
IFCModels.models = [...IFCModels.models, model];
|
||||||
|
|
||||||
console.log(`IFC model "${file.name}" loaded with ID: ${ifcId}`);
|
console.log(`IFC model "${file.name}" loaded with ID: ${ifcId}`);
|
||||||
return model;
|
return model;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -152,10 +152,10 @@ export async function unloadIfc(modelId: string) {
|
|||||||
try {
|
try {
|
||||||
// Unload model
|
// Unload model
|
||||||
await wasm.unloadIfc(modelId);
|
await wasm.unloadIfc(modelId);
|
||||||
|
|
||||||
// Remove from models list
|
// Remove from models list
|
||||||
IFCModels.models = IFCModels.models.filter(model => model.id !== modelId);
|
IFCModels.models = IFCModels.models.filter(model => model.id !== modelId);
|
||||||
|
|
||||||
console.log(`IFC model with ID ${modelId} unloaded`);
|
console.log(`IFC model with ID ${modelId} unloaded`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to unload IFC model:', error);
|
console.error('Failed to unload IFC model:', error);
|
||||||
@@ -173,10 +173,10 @@ export async function auditIfc(modelId: string, idsData: string | Uint8Array | A
|
|||||||
} else {
|
} else {
|
||||||
idsBytes = idsData;
|
idsBytes = idsData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run audit
|
// Run audit
|
||||||
const auditResult = await wasm.auditIfc(modelId, idsBytes) as { json: AuditReportData; html: string };
|
const auditResult = await wasm.auditIfc(modelId, idsBytes) as { json: AuditReportData; html: string };
|
||||||
|
|
||||||
console.log(`Audit completed for model ${modelId}`);
|
console.log(`Audit completed for model ${modelId}`);
|
||||||
return auditResult;
|
return auditResult;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -194,7 +194,7 @@ export async function openIfc() {
|
|||||||
const fileInput = document.createElement('input');
|
const fileInput = document.createElement('input');
|
||||||
fileInput.type = 'file';
|
fileInput.type = 'file';
|
||||||
fileInput.accept = '.ifc';
|
fileInput.accept = '.ifc';
|
||||||
|
|
||||||
fileInput.onchange = async (event) => {
|
fileInput.onchange = async (event) => {
|
||||||
const target = event.target as HTMLInputElement | null;
|
const target = event.target as HTMLInputElement | null;
|
||||||
const file = target?.files?.[0];
|
const file = target?.files?.[0];
|
||||||
@@ -202,13 +202,13 @@ export async function openIfc() {
|
|||||||
reject(new Error('No file selected'));
|
reject(new Error('No file selected'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's an IFC file
|
// Check if it's an IFC file
|
||||||
if (!file.name.toLowerCase().endsWith('.ifc')) {
|
if (!file.name.toLowerCase().endsWith('.ifc')) {
|
||||||
reject(new Error('Please select a valid IFC file (.ifc)'));
|
reject(new Error('Please select a valid IFC file (.ifc)'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await loadIfc(file);
|
await loadIfc(file);
|
||||||
resolve();
|
resolve();
|
||||||
@@ -216,7 +216,7 @@ export async function openIfc() {
|
|||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fileInput.onerror = () => reject(new Error('Failed to open file picker'));
|
fileInput.onerror = () => reject(new Error('Failed to open file picker'));
|
||||||
fileInput.click();
|
fileInput.click();
|
||||||
});
|
});
|
||||||
@@ -234,7 +234,7 @@ export function createAuditReport(
|
|||||||
): AuditReport | undefined {
|
): AuditReport | undefined {
|
||||||
const model = getIfcById(modelId);
|
const model = getIfcById(modelId);
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const auditReport: AuditReport = {
|
const auditReport: AuditReport = {
|
||||||
id: id(),
|
id: id(),
|
||||||
modelId: modelId,
|
modelId: modelId,
|
||||||
@@ -244,7 +244,7 @@ export function createAuditReport(
|
|||||||
data: auditData,
|
data: auditData,
|
||||||
htmlReport: htmlReport
|
htmlReport: htmlReport
|
||||||
};
|
};
|
||||||
|
|
||||||
IFCModels.audits.unshift(auditReport);
|
IFCModels.audits.unshift(auditReport);
|
||||||
return auditReport;
|
return auditReport;
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ export async function downloadAuditReport(auditId: string) {
|
|||||||
if (!audit || !audit.htmlReport) {
|
if (!audit || !audit.htmlReport) {
|
||||||
throw new Error('HTML report not available for this audit');
|
throw new Error('HTML report not available for this audit');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get IDS document title for filename
|
// Get IDS document title for filename
|
||||||
let filename = 'report.html';
|
let filename = 'report.html';
|
||||||
if (audit.document && IDS.Module.documents[audit.document]) {
|
if (audit.document && IDS.Module.documents[audit.document]) {
|
||||||
@@ -274,15 +274,15 @@ export async function downloadAuditReport(auditId: string) {
|
|||||||
const title = doc.info?.title || 'untitled';
|
const title = doc.info?.title || 'untitled';
|
||||||
filename = `report_${title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.html`;
|
filename = `report_${title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.html`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const blob = new Blob([audit.htmlReport], { type: 'text/html' });
|
const blob = new Blob([audit.htmlReport], { type: 'text/html' });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.href = url;
|
link.href = url;
|
||||||
link.download = filename;
|
link.download = filename;
|
||||||
link.style.display = 'none';
|
link.style.display = 'none';
|
||||||
|
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
@@ -293,47 +293,47 @@ export async function runAudit() {
|
|||||||
if (IFCModels.models.length === 0) {
|
if (IFCModels.models.length === 0) {
|
||||||
throw new Error('Please load an IFC model first');
|
throw new Error('Please load an IFC model first');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IDS.Module.activeDocument) {
|
if (!IDS.Module.activeDocument) {
|
||||||
throw new Error('Please create or open an IDS document first');
|
throw new Error('Please create or open an IDS document first');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear previous audit reports
|
// Clear previous audit reports
|
||||||
IFCModels.audits = [];
|
IFCModels.audits = [];
|
||||||
|
|
||||||
// Get the active IDS document XML
|
// Get the active IDS document XML
|
||||||
const idsXml = await IDS.exportActiveDocument();
|
const idsXml = await IDS.exportActiveDocument();
|
||||||
if (!idsXml) {
|
if (!idsXml) {
|
||||||
throw new Error('Failed to export IDS document');
|
throw new Error('Failed to export IDS document');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run audit on all loaded models
|
// Run audit on all loaded models
|
||||||
let firstAuditReport: AuditReport | undefined;
|
let firstAuditReport: AuditReport | undefined;
|
||||||
for (const model of IFCModels.models) {
|
for (const model of IFCModels.models) {
|
||||||
const result = await auditIfc(model.id, idsXml);
|
const result = await auditIfc(model.id, idsXml);
|
||||||
|
|
||||||
// Extract JSON and HTML reports from the result
|
// Extract JSON and HTML reports from the result
|
||||||
const jsonData = result.json || null;
|
const jsonData = result.json || null;
|
||||||
const htmlReport = result.html || null;
|
const htmlReport = result.html || null;
|
||||||
|
|
||||||
if (!jsonData) {
|
if (!jsonData) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auditReport = createAuditReport(model.id, IDS.Module.activeDocument as string, jsonData, htmlReport);
|
const auditReport = createAuditReport(model.id, IDS.Module.activeDocument as string, jsonData, htmlReport);
|
||||||
|
|
||||||
// Store the first audit report to open in viewer
|
// Store the first audit report to open in viewer
|
||||||
if (!firstAuditReport) {
|
if (!firstAuditReport) {
|
||||||
firstAuditReport = auditReport;
|
firstAuditReport = auditReport;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch to viewer mode and set the first audit report as active
|
// Switch to viewer mode and set the first audit report as active
|
||||||
if (firstAuditReport && IDS.Module.activeDocument) {
|
if (firstAuditReport && IDS.Module.activeDocument) {
|
||||||
IDS.setDocumentState(IDS.Module.activeDocument, {
|
IDS.setDocumentState(IDS.Module.activeDocument, {
|
||||||
viewMode: 'viewer',
|
viewMode: 'viewer',
|
||||||
auditReport: firstAuditReport.id
|
auditReport: firstAuditReport.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return firstAuditReport;
|
return firstAuditReport;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,33 +59,33 @@ export const connect = () => new Promise<void>((resolve, reject) => {
|
|||||||
resolve();
|
resolve();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Bonsai.socket = io(`ws://127.0.0.1:${Bonsai.port}/ifctester`, {
|
Bonsai.socket = io(`ws://127.0.0.1:${Bonsai.port}/ifctester`, {
|
||||||
transports: ['websocket'],
|
transports: ['websocket'],
|
||||||
reconnection: false,
|
reconnection: false,
|
||||||
timeout: 5000
|
timeout: 5000
|
||||||
});
|
});
|
||||||
|
|
||||||
Bonsai.socket.on('connect', () => {
|
Bonsai.socket.on('connect', () => {
|
||||||
Bonsai.connected = true;
|
Bonsai.connected = true;
|
||||||
success('Connected to Bonsai');
|
success('Connected to Bonsai');
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
Bonsai.socket.on('disconnect', () => {
|
Bonsai.socket.on('disconnect', () => {
|
||||||
Bonsai.connected = false;
|
Bonsai.connected = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
Bonsai.socket.on('connect_error', (err: Error) => {
|
Bonsai.socket.on('connect_error', (err: Error) => {
|
||||||
Bonsai.connected = false;
|
Bonsai.connected = false;
|
||||||
error(`Failed to connect to Bonsai: ${err.message}`);
|
error(`Failed to connect to Bonsai: ${err.message}`);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
Bonsai.socket.on('audit_result', handleAuditResult);
|
Bonsai.socket.on('audit_result', handleAuditResult);
|
||||||
Bonsai.socket.on('error', handleAuditError);
|
Bonsai.socket.on('error', handleAuditError);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message = err instanceof Error ? err.message : String(err);
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
error(`Failed to connect to Bonsai: ${message}`);
|
error(`Failed to connect to Bonsai: ${message}`);
|
||||||
@@ -113,35 +113,35 @@ export const runAudit = async () => {
|
|||||||
if (!Bonsai.socket || !Bonsai.connected || !IDS.Module.activeDocument) {
|
if (!Bonsai.socket || !Bonsai.connected || !IDS.Module.activeDocument) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Bonsai.auditing = true;
|
Bonsai.auditing = true;
|
||||||
|
|
||||||
const activeDoc = IDS.Module.documents[IDS.Module.activeDocument];
|
const activeDoc = IDS.Module.documents[IDS.Module.activeDocument];
|
||||||
if (!activeDoc) throw new Error('No active IDS document');
|
if (!activeDoc) throw new Error('No active IDS document');
|
||||||
|
|
||||||
// Convert IDS document to XML string
|
// Convert IDS document to XML string
|
||||||
const idsXml = await IDS.exportActiveDocument();
|
const idsXml = await IDS.exportActiveDocument();
|
||||||
if (!idsXml) {
|
if (!idsXml) {
|
||||||
throw new Error('Failed to export IDS document');
|
throw new Error('Failed to export IDS document');
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestId = id();
|
const requestId = id();
|
||||||
const socket = Bonsai.socket;
|
const socket = Bonsai.socket;
|
||||||
if (!socket) {
|
if (!socket) {
|
||||||
throw new Error('Bonsai socket not connected');
|
throw new Error('Bonsai socket not connected');
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<string | null>((resolve, reject) => {
|
return new Promise<string | null>((resolve, reject) => {
|
||||||
// Store request with resolve/reject functions
|
// Store request with resolve/reject functions
|
||||||
pendingAudits.set(requestId, { resolve, reject });
|
pendingAudits.set(requestId, { resolve, reject });
|
||||||
|
|
||||||
socket.emit('audit_ids', {
|
socket.emit('audit_ids', {
|
||||||
id: requestId,
|
id: requestId,
|
||||||
ids: idsXml
|
ids: idsXml
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Bonsai.auditing = false;
|
Bonsai.auditing = false;
|
||||||
const message = err instanceof Error ? err.message : String(err);
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
@@ -156,19 +156,19 @@ export const runAudit = async () => {
|
|||||||
*/
|
*/
|
||||||
const handleAuditResult = (data: AuditResultPayload) => {
|
const handleAuditResult = (data: AuditResultPayload) => {
|
||||||
if (!data.id || !data.json_report) return;
|
if (!data.id || !data.json_report) return;
|
||||||
|
|
||||||
const pendingAudit = pendingAudits.get(data.id);
|
const pendingAudit = pendingAudits.get(data.id);
|
||||||
if (!pendingAudit) {
|
if (!pendingAudit) {
|
||||||
console.warn('[Bonsai] Received response for unknown audit ID:', data.id);
|
console.warn('[Bonsai] Received response for unknown audit ID:', data.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingAudits.delete(data.id);
|
pendingAudits.delete(data.id);
|
||||||
const { resolve } = pendingAudit;
|
const { resolve } = pendingAudit;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const reportData = JSON.parse(data.json_report) as AuditReportData;
|
const reportData = JSON.parse(data.json_report) as AuditReportData;
|
||||||
|
|
||||||
const auditReport: AuditReport = {
|
const auditReport: AuditReport = {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
modelId: `bonsai:${data.id}`,
|
modelId: `bonsai:${data.id}`,
|
||||||
@@ -178,16 +178,16 @@ const handleAuditResult = (data: AuditResultPayload) => {
|
|||||||
data: reportData,
|
data: reportData,
|
||||||
htmlReport: data.html_report
|
htmlReport: data.html_report
|
||||||
};
|
};
|
||||||
|
|
||||||
// Store audit report
|
// Store audit report
|
||||||
IFCModels.audits.unshift(auditReport);
|
IFCModels.audits.unshift(auditReport);
|
||||||
|
|
||||||
Bonsai.auditing = false;
|
Bonsai.auditing = false;
|
||||||
success('Audit completed (Bonsai)');
|
success('Audit completed (Bonsai)');
|
||||||
|
|
||||||
// Resolve promise with audit ID
|
// Resolve promise with audit ID
|
||||||
resolve(data.id);
|
resolve(data.id);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Bonsai.auditing = false;
|
Bonsai.auditing = false;
|
||||||
const message = err instanceof Error ? err.message : String(err);
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
@@ -202,16 +202,16 @@ const handleAuditResult = (data: AuditResultPayload) => {
|
|||||||
*/
|
*/
|
||||||
const handleAuditError = (data: AuditErrorPayload) => {
|
const handleAuditError = (data: AuditErrorPayload) => {
|
||||||
if (!data.id) return;
|
if (!data.id) return;
|
||||||
|
|
||||||
const pendingAudit = pendingAudits.get(data.id);
|
const pendingAudit = pendingAudits.get(data.id);
|
||||||
if (!pendingAudit) {
|
if (!pendingAudit) {
|
||||||
console.warn('[Bonsai] Received error for unknown audit ID:', data.id);
|
console.warn('[Bonsai] Received error for unknown audit ID:', data.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingAudits.delete(data.id);
|
pendingAudits.delete(data.id);
|
||||||
const { resolve } = pendingAudit;
|
const { resolve } = pendingAudit;
|
||||||
|
|
||||||
Bonsai.auditing = false;
|
Bonsai.auditing = false;
|
||||||
error(`Audit failed (Bonsai): ${data.error ?? "Unknown error"}`);
|
error(`Audit failed (Bonsai): ${data.error ?? "Unknown error"}`);
|
||||||
resolve(null);
|
resolve(null);
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export async function createDocument() {
|
|||||||
export async function deleteDocument(id: string) {
|
export async function deleteDocument(id: string) {
|
||||||
// Clear any audit reports generated using this IDS document
|
// Clear any audit reports generated using this IDS document
|
||||||
clearIdsAuditReports(id);
|
clearIdsAuditReports(id);
|
||||||
|
|
||||||
delete Module.documents[id];
|
delete Module.documents[id];
|
||||||
delete Module.states[id];
|
delete Module.states[id];
|
||||||
|
|
||||||
@@ -73,18 +73,18 @@ export async function deleteDocument(id: string) {
|
|||||||
// We need this because the backend exports with xs: prefix, yet expects a dict without prefixes.
|
// We need this because the backend exports with xs: prefix, yet expects a dict without prefixes.
|
||||||
function normalizeIdsDict(obj: unknown): unknown {
|
function normalizeIdsDict(obj: unknown): unknown {
|
||||||
if (typeof obj !== 'object' || obj === null) return obj;
|
if (typeof obj !== 'object' || obj === null) return obj;
|
||||||
|
|
||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
return obj.map(normalizeIdsDict);
|
return obj.map(normalizeIdsDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result: Record<string, unknown> = {};
|
const result: Record<string, unknown> = {};
|
||||||
for (const [key, value] of Object.entries(obj)) {
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
if (key === 'xs:restriction' && Array.isArray(value) && value.length > 0) {
|
if (key === 'xs:restriction' && Array.isArray(value) && value.length > 0) {
|
||||||
// Convert xs:restriction array to restriction object
|
// Convert xs:restriction array to restriction object
|
||||||
const restriction = value[0] as Record<string, unknown>;
|
const restriction = value[0] as Record<string, unknown>;
|
||||||
const newRestriction: Record<string, unknown> = {};
|
const newRestriction: Record<string, unknown> = {};
|
||||||
|
|
||||||
for (const [restrictionKey, restrictionValue] of Object.entries(restriction)) {
|
for (const [restrictionKey, restrictionValue] of Object.entries(restriction)) {
|
||||||
if (restrictionKey.startsWith('xs:')) {
|
if (restrictionKey.startsWith('xs:')) {
|
||||||
// Remove xs: prefix from keys
|
// Remove xs: prefix from keys
|
||||||
@@ -94,13 +94,13 @@ function normalizeIdsDict(obj: unknown): unknown {
|
|||||||
newRestriction[restrictionKey] = restrictionValue;
|
newRestriction[restrictionKey] = restrictionValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.restriction = newRestriction;
|
result.restriction = newRestriction;
|
||||||
} else {
|
} else {
|
||||||
result[key] = normalizeIdsDict(value);
|
result[key] = normalizeIdsDict(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ export async function openDocument() {
|
|||||||
};
|
};
|
||||||
fileInput.type = 'file';
|
fileInput.type = 'file';
|
||||||
fileInput.accept = '.ids,.xml';
|
fileInput.accept = '.ids,.xml';
|
||||||
|
|
||||||
fileInput.onchange = async (event) => {
|
fileInput.onchange = async (event) => {
|
||||||
const target = event.target as HTMLInputElement | null;
|
const target = event.target as HTMLInputElement | null;
|
||||||
const file = target?.files?.[0];
|
const file = target?.files?.[0];
|
||||||
@@ -119,7 +119,7 @@ export async function openDocument() {
|
|||||||
reject(new Error('No file selected'));
|
reject(new Error('No file selected'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = async (e) => {
|
reader.onload = async (e) => {
|
||||||
@@ -130,10 +130,10 @@ export async function openDocument() {
|
|||||||
|
|
||||||
// Add document to list and set as active
|
// Add document to list and set as active
|
||||||
Module.documents[docId] = doc;
|
Module.documents[docId] = doc;
|
||||||
|
|
||||||
// Initialize document state and switch to viewer mode
|
// Initialize document state and switch to viewer mode
|
||||||
setDocumentState(docId, { viewMode: 'viewer' });
|
setDocumentState(docId, { viewMode: 'viewer' });
|
||||||
|
|
||||||
Module.activeDocument = docId;
|
Module.activeDocument = docId;
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
@@ -147,11 +147,11 @@ export async function openDocument() {
|
|||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fileInput.oncancel = () => {
|
fileInput.oncancel = () => {
|
||||||
reject(new Error('File selection cancelled'));
|
reject(new Error('File selection cancelled'));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Trigger the file dialog
|
// Trigger the file dialog
|
||||||
fileInput.click();
|
fileInput.click();
|
||||||
});
|
});
|
||||||
@@ -175,7 +175,7 @@ export async function exportDocument(docId: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const xmlString = await wasm.exportIDS(doc as Record<string, unknown>) as string;
|
const xmlString = await wasm.exportIDS(doc as Record<string, unknown>) as string;
|
||||||
|
|
||||||
// Create and download file
|
// Create and download file
|
||||||
const blob = new Blob([xmlString], { type: 'application/xml' });
|
const blob = new Blob([xmlString], { type: 'application/xml' });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
@@ -290,7 +290,7 @@ export function stringifyFacet(
|
|||||||
|
|
||||||
const usage = getSpecUsage(spec);
|
const usage = getSpecUsage(spec);
|
||||||
const descriptions: string[] = [];
|
const descriptions: string[] = [];
|
||||||
|
|
||||||
// Entity facet
|
// Entity facet
|
||||||
if (facetType === "entity") {
|
if (facetType === "entity") {
|
||||||
if (clauseType === "applicability") {
|
if (clauseType === "applicability") {
|
||||||
@@ -377,13 +377,13 @@ export function stringifyFacet(
|
|||||||
if (clauseType === "requirements" && "@cardinality" in facet && facet["@cardinality"] === "prohibited") {
|
if (clauseType === "requirements" && "@cardinality" in facet && facet["@cardinality"] === "prohibited") {
|
||||||
isProhibited = !isProhibited;
|
isProhibited = !isProhibited;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isProhibited)
|
if (isProhibited)
|
||||||
combined = combined.replace("Shall", "Shall not").replace("shall", "shall not");
|
combined = combined.replace("Shall", "Shall not").replace("shall", "shall not");
|
||||||
|
|
||||||
if (clauseType === "requirements" && "@cardinality" in facet && facet["@cardinality"] === "optional")
|
if (clauseType === "requirements" && "@cardinality" in facet && facet["@cardinality"] === "optional")
|
||||||
combined = combined.replace("Shall", "May").replace("shall", "may");
|
combined = combined.replace("Shall", "May").replace("shall", "may");
|
||||||
|
|
||||||
return renderFacetString(combined);
|
return renderFacetString(combined);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,27 +398,27 @@ function stringifyValue(value?: FacetValue) {
|
|||||||
// Converts restriction objects to human-readable strings
|
// Converts restriction objects to human-readable strings
|
||||||
function stringifyRestriction(restriction: Restriction) {
|
function stringifyRestriction(restriction: Restriction) {
|
||||||
if (!restriction) return "";
|
if (!restriction) return "";
|
||||||
|
|
||||||
// Handle enumeration
|
// Handle enumeration
|
||||||
if (restriction.enumeration && Array.isArray(restriction.enumeration)) {
|
if (restriction.enumeration && Array.isArray(restriction.enumeration)) {
|
||||||
const values = restriction.enumeration.map(item => `**${item['@value']}**` || '').filter(v => v);
|
const values = restriction.enumeration.map(item => `**${item['@value']}**` || '').filter(v => v);
|
||||||
return values.length > 0 ? `is one of ${values.join(", ")}` : "has enumeration restriction";
|
return values.length > 0 ? `is one of ${values.join(", ")}` : "has enumeration restriction";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle pattern
|
// Handle pattern
|
||||||
if (restriction.pattern && Array.isArray(restriction.pattern) && restriction.pattern.length > 0) {
|
if (restriction.pattern && Array.isArray(restriction.pattern) && restriction.pattern.length > 0) {
|
||||||
const pattern = `\`${restriction.pattern[0]['@value']}\`` || '';
|
const pattern = `\`${restriction.pattern[0]['@value']}\`` || '';
|
||||||
return pattern ? `matches pattern ${pattern}` : "has pattern restriction";
|
return pattern ? `matches pattern ${pattern}` : "has pattern restriction";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle length restrictions
|
// Handle length restrictions
|
||||||
if (restriction.length && Array.isArray(restriction.length) && restriction.length.length > 0) {
|
if (restriction.length && Array.isArray(restriction.length) && restriction.length.length > 0) {
|
||||||
const length = `**${restriction.length[0]['@value']}**` || '';
|
const length = `**${restriction.length[0]['@value']}**` || '';
|
||||||
return length ? `has length ${length}` : "has length restriction";
|
return length ? `has length ${length}` : "has length restriction";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle range restrictions
|
// Handle range restrictions
|
||||||
if (restriction.minInclusive || restriction.maxInclusive ||
|
if (restriction.minInclusive || restriction.maxInclusive ||
|
||||||
restriction.minExclusive || restriction.maxExclusive) {
|
restriction.minExclusive || restriction.maxExclusive) {
|
||||||
const parts = [];
|
const parts = [];
|
||||||
if (restriction.minInclusive && restriction.minInclusive.length > 0) {
|
if (restriction.minInclusive && restriction.minInclusive.length > 0) {
|
||||||
@@ -435,7 +435,7 @@ function stringifyRestriction(restriction: Restriction) {
|
|||||||
}
|
}
|
||||||
return parts.length > 0 ? `is in range ${parts.join(", ")}` : "has range restriction";
|
return parts.length > 0 ? `is in range ${parts.join(", ")}` : "has range restriction";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle length range restrictions
|
// Handle length range restrictions
|
||||||
if (restriction.minLength || restriction.maxLength) {
|
if (restriction.minLength || restriction.maxLength) {
|
||||||
const parts = [];
|
const parts = [];
|
||||||
@@ -447,16 +447,16 @@ function stringifyRestriction(restriction: Restriction) {
|
|||||||
}
|
}
|
||||||
return parts.length > 0 ? `has ${parts.join(", ")}` : "has length range restriction";
|
return parts.length > 0 ? `has ${parts.join(", ")}` : "has length range restriction";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "has complex restriction";
|
return "has complex restriction";
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFacetString(text: string): string {
|
function renderFacetString(text: string): string {
|
||||||
// Convert **text** to <strong>text</strong>
|
// Convert **text** to <strong>text</strong>
|
||||||
const withStrong = text.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
const withStrong = text.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
||||||
|
|
||||||
// Convert `text` to <code>text</code>
|
// Convert `text` to <code>text</code>
|
||||||
const withCode = withStrong.replace(/`([^`]+)`/g, '<code>$1</code>');
|
const withCode = withStrong.replace(/`([^`]+)`/g, '<code>$1</code>');
|
||||||
|
|
||||||
return withCode;
|
return withCode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class WASMModule extends EventEmitter {
|
|||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.pendingMessages.set(id, { resolve, reject });
|
this.pendingMessages.set(id, { resolve, reject });
|
||||||
|
|
||||||
worker.postMessage({
|
worker.postMessage({
|
||||||
type,
|
type,
|
||||||
payload,
|
payload,
|
||||||
@@ -86,7 +86,7 @@ class WASMModule extends EventEmitter {
|
|||||||
|
|
||||||
_handleWorkerMessage({ type, payload, id }: WorkerResponse) {
|
_handleWorkerMessage({ type, payload, id }: WorkerResponse) {
|
||||||
const pendingMessage = this.pendingMessages.get(id);
|
const pendingMessage = this.pendingMessages.get(id);
|
||||||
|
|
||||||
if (!pendingMessage) {
|
if (!pendingMessage) {
|
||||||
console.warn('[WASM] Received response for unknown message ID:', id);
|
console.warn('[WASM] Received response for unknown message ID:', id);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ let PartOf: any;
|
|||||||
|
|
||||||
export async function init(pdide: any) {
|
export async function init(pdide: any) {
|
||||||
pyodide = pdide;
|
pyodide = pdide;
|
||||||
|
|
||||||
await pyodide.loadPackagesFromImports(`
|
await pyodide.loadPackagesFromImports(`
|
||||||
import ifctester.ids
|
import ifctester.ids
|
||||||
import ifctester.facet
|
import ifctester.facet
|
||||||
@@ -25,7 +25,7 @@ export async function init(pdide: any) {
|
|||||||
// Import the core IDS classes
|
// Import the core IDS classes
|
||||||
Ids = pyodide.pyimport("ifctester.ids").Ids;
|
Ids = pyodide.pyimport("ifctester.ids").Ids;
|
||||||
Specification = pyodide.pyimport("ifctester.ids").Specification;
|
Specification = pyodide.pyimport("ifctester.ids").Specification;
|
||||||
|
|
||||||
// Import facet classes
|
// Import facet classes
|
||||||
Entity = pyodide.pyimport("ifctester.facet").Entity;
|
Entity = pyodide.pyimport("ifctester.facet").Entity;
|
||||||
Attribute = pyodide.pyimport("ifctester.facet").Attribute;
|
Attribute = pyodide.pyimport("ifctester.facet").Attribute;
|
||||||
@@ -56,13 +56,13 @@ export function validateIDS(idsObj: Record<string, unknown>): boolean {
|
|||||||
const ids_raw = _idsToInstance(idsObj)
|
const ids_raw = _idsToInstance(idsObj)
|
||||||
const tempFilename = `temp_${Date.now()}.xml`;
|
const tempFilename = `temp_${Date.now()}.xml`;
|
||||||
const isValid = ids_raw.to_xml(tempFilename); // to_xml validates the XML as well, as far as I understand
|
const isValid = ids_raw.to_xml(tempFilename); // to_xml validates the XML as well, as far as I understand
|
||||||
|
|
||||||
pyodide.runPython(`
|
pyodide.runPython(`
|
||||||
import os
|
import os
|
||||||
if os.path.exists("${tempFilename}"):
|
if os.path.exists("${tempFilename}"):
|
||||||
os.remove("${tempFilename}")
|
os.remove("${tempFilename}")
|
||||||
`);
|
`);
|
||||||
|
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,4 +3,4 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export {default as Home} from './Home/index.svelte';
|
export {default as Home} from './Home/index.svelte';
|
||||||
export {default as NotFound} from './NotFound/index.svelte';
|
export {default as NotFound} from './NotFound/index.svelte';
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ const routes = {
|
|||||||
'*': NotFound,
|
'*': NotFound,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default routes;
|
export default routes;
|
||||||
|
|||||||
Reference in New Issue
Block a user