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
5 changes: 5 additions & 0 deletions flow-core/src/deps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { normalize } from "https://deno.land/std@0.224.0/path/mod.ts";
export { assertEquals, assertThrows, assertNotStrictEquals } from "https://deno.land/std@0.224.0/assert/mod.ts";
export { basename, dirname, join, resolve } from "https://deno.land/std@0.224.0/path/mod.ts";
export { existsSync } from "https://deno.land/std@0.224.0/fs/mod.ts";
export { ensureDir } from "https://deno.land/std@0.224.0/fs/ensure_dir.ts";
138 changes: 0 additions & 138 deletions flow-core/src/mesh-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,141 +49,3 @@ export const MESH = {
FLOW_SERVICE_ONTOLOGY: "https://semantic-flow.github.io/ontology/flow-service/"
} as const;

// Usage throughout codebase


export function getHandlePath(nodePath: string): string {
return `${nodePath}/${MESH.HANDLE_DIR}/`;
}

export function getAssetsPath(nodePath: string): string {
return `${nodePath}/${MESH.ASSETS_DIR}/`;
}

// config
export function getConfigFlowPath(nodePath: string): string {
return `${nodePath}/${MESH.CONFIG_FLOW_DIR}/`;
}

export function getCurrentConfigSnapshotPath(nodePath: string): string {
return `${getConfigFlowPath(nodePath)}/${MESH.CURRENT_SNAPSHOT_DIR}/`;
}

export function getCurrentConfigDistPath(nodePath: string): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getCurrentConfigSnapshotPath(nodePath)}${lastSegment}_${MESH.CONFIG}_${MESH.CURRENT}.jsonld`;
}

export function getNextConfigSnapshotPath(nodePath: string): string {
return `${getConfigFlowPath(nodePath)}/${MESH.NEXT_SNAPSHOT_DIR}/`;
}

export function getNextConfigDistPath(nodePath: string): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getNextConfigSnapshotPath(nodePath)}${lastSegment}_${MESH.CONFIG}_${MESH.NEXT}.jsonld`;
}

export function getVersionConfigSnapshotPath(nodePath: string, version: number): string {
return `${getConfigFlowPath(nodePath)}/${MESH.VERSION_SNAPSHOT_PREFIX}${version}/`;
}

export function getVersionConfigDistPath(nodePath: string, version: number): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getVersionConfigSnapshotPath(nodePath, version)}${lastSegment}_${MESH.CONFIG}_${MESH.VERSION_SNAPSHOT_PREFIX}${version}.jsonld`;
}

// meta
export function getMetaFlowPath(nodePath: string): string {
return `${nodePath}/${MESH.META_FLOW_DIR}/`;
}

export function getCurrentMetaSnapshotPath(nodePath: string): string {
return `${getMetaFlowPath(nodePath)}/${MESH.CURRENT_SNAPSHOT_DIR}/`;
}

export function getCurrentMetaDistPath(nodePath: string): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getCurrentMetaSnapshotPath(nodePath)}${lastSegment}_${MESH.META}_${MESH.CURRENT}.jsonld`;
}

export function getNextMetaSnapshotPath(nodePath: string): string {
return `${getMetaFlowPath(nodePath)}/${MESH.NEXT_SNAPSHOT_DIR}/`;
}

export function getNextMetaDistPath(nodePath: string): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getNextMetaSnapshotPath(nodePath)}${lastSegment}_${MESH.META}_${MESH.NEXT}.jsonld`;
}

export function getVersionMetaSnapshotPath(nodePath: string, version: number): string {
return `${getMetaFlowPath(nodePath)}/${MESH.VERSION_SNAPSHOT_PREFIX}${version}/`;
}

export function getVersionMetaDistPath(nodePath: string, version: number): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getVersionMetaSnapshotPath(nodePath, version)}${lastSegment}_${MESH.META}_${MESH.VERSION_SNAPSHOT_PREFIX}${version}.jsonld`;
}

// REF
export function getRefFlowPath(nodePath: string): string {
return `${nodePath}/${MESH.REF_FLOW_DIR}/`;
}

export function getCurrentRefSnapshotPath(nodePath: string): string {
return `${getRefFlowPath(nodePath)}/${MESH.CURRENT_SNAPSHOT_DIR}/`;
}

export function getCurrentRefDistPath(nodePath: string): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getCurrentRefSnapshotPath(nodePath)}${lastSegment}_${MESH.REF}_${MESH.CURRENT}.jsonld`;
}

export function getNextRefSnapshotPath(nodePath: string): string {
return `${getRefFlowPath(nodePath)}/${MESH.NEXT_SNAPSHOT_DIR}/`;
}

export function getNextRefDistPath(nodePath: string): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getNextRefSnapshotPath(nodePath)}${lastSegment}_${MESH.REF}_${MESH.NEXT}.jsonld`;
}

export function getVersionRefSnapshotPath(nodePath: string, version: number): string {
return `${getRefFlowPath(nodePath)}/${MESH.VERSION_SNAPSHOT_PREFIX}${version}/`;
}

export function getVersionRefDistPath(nodePath: string, version: number): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getVersionRefSnapshotPath(nodePath, version)}${lastSegment}_${MESH.REF}_${MESH.VERSION_SNAPSHOT_PREFIX}${version}.jsonld`;
}

// data
export function getDataFlowPath(nodePath: string): string {
return `${nodePath}/${MESH.DATA_FLOW_DIR}/`;
}

export function getCurrentDataSnapshotPath(nodePath: string): string {
return `${getDataFlowPath(nodePath)}/${MESH.CURRENT_SNAPSHOT_DIR}/`;
}

export function getCurrentDataDistPath(nodePath: string): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getCurrentDataSnapshotPath(nodePath)}${lastSegment}_${MESH.DATA}_${MESH.CURRENT}.jsonld`;
}

export function getNextDataSnapshotPath(nodePath: string): string {
return `${getDataFlowPath(nodePath)}/${MESH.NEXT_SNAPSHOT_DIR}/`;
}

export function getNextDataDistPath(nodePath: string): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getNextDataSnapshotPath(nodePath)}${lastSegment}_${MESH.DATA}_${MESH.NEXT}.jsonld`;
}

export function getVersionDataSnapshotPath(nodePath: string, version: number): string {
return `${getDataFlowPath(nodePath)}/${MESH.VERSION_SNAPSHOT_PREFIX}${version}/`;
}

export function getVersionDataDistPath(nodePath: string, version: number): string {
const lastSegment = nodePath.substring(nodePath.lastIndexOf("/") + 1);
return `${getVersionDataSnapshotPath(nodePath, version)}${lastSegment}_${MESH.DATA}_${MESH.VERSION_SNAPSHOT_PREFIX}${version}.jsonld`;
}
1 change: 1 addition & 0 deletions flow-core/src/utils/api-param-path-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Utility functions for pseudo-path handling (using ~ instead of /) for API parameters
145 changes: 145 additions & 0 deletions flow-core/src/utils/mesh-path-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/**
* Utility functions for mesh path operations
*/

import { MESH } from '../mesh-constants.ts';
import { getLastPathSegment } from './path-utils.ts';

// Usage throughout codebase


export function getHandlePath(nodePath: string): string {
return `${nodePath}/${MESH.HANDLE_DIR}/`;
}

export function getAssetsPath(nodePath: string): string {
return `${nodePath}/${MESH.ASSETS_DIR}/`;
}

// config
export function getConfigFlowPath(nodePath: string): string {
return `${nodePath}/${MESH.CONFIG_FLOW_DIR}/`;
}

export function getCurrentConfigSnapshotPath(nodePath: string): string {
return `${getConfigFlowPath(nodePath)}/${MESH.CURRENT_SNAPSHOT_DIR}/`;
}

export function getCurrentConfigDistPath(nodePath: string): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getCurrentConfigSnapshotPath(nodePath)}${lastSegment}_${MESH.CONFIG}_${MESH.CURRENT}.jsonld`;
}

export function getNextConfigSnapshotPath(nodePath: string): string {
return `${getConfigFlowPath(nodePath)}/${MESH.NEXT_SNAPSHOT_DIR}/`;
}

export function getNextConfigDistPath(nodePath: string): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getNextConfigSnapshotPath(nodePath)}${lastSegment}_${MESH.CONFIG}_${MESH.NEXT}.jsonld`;
}

export function getVersionConfigSnapshotPath(nodePath: string, version: number): string {
return `${getConfigFlowPath(nodePath)}/${MESH.VERSION_SNAPSHOT_PREFIX}${version}/`;
}

export function getVersionConfigDistPath(nodePath: string, version: number): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getVersionConfigSnapshotPath(nodePath, version)}${lastSegment}_${MESH.CONFIG}_${MESH.VERSION_SNAPSHOT_PREFIX}${version}.jsonld`;
}

// meta
export function getMetaFlowPath(nodePath: string): string {
return `${nodePath}/${MESH.META_FLOW_DIR}/`;
}

export function getCurrentMetaSnapshotPath(nodePath: string): string {
return `${getMetaFlowPath(nodePath)}/${MESH.CURRENT_SNAPSHOT_DIR}/`;
}

export function getCurrentMetaDistPath(nodePath: string): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getCurrentMetaSnapshotPath(nodePath)}${lastSegment}_${MESH.META}_${MESH.CURRENT}.jsonld`;
}

export function getNextMetaSnapshotPath(nodePath: string): string {
return `${getMetaFlowPath(nodePath)}/${MESH.NEXT_SNAPSHOT_DIR}/`;
}

export function getNextMetaDistPath(nodePath: string): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getNextMetaSnapshotPath(nodePath)}${lastSegment}_${MESH.META}_${MESH.NEXT}.jsonld`;
}

export function getVersionMetaSnapshotPath(nodePath: string, version: number): string {
return `${getMetaFlowPath(nodePath)}/${MESH.VERSION_SNAPSHOT_PREFIX}${version}/`;
}

export function getVersionMetaDistPath(nodePath: string, version: number): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getVersionMetaSnapshotPath(nodePath, version)}${lastSegment}_${MESH.META}_${MESH.VERSION_SNAPSHOT_PREFIX}${version}.jsonld`;
}

// REF
export function getRefFlowPath(nodePath: string): string {
return `${nodePath}/${MESH.REF_FLOW_DIR}/`;
}

export function getCurrentRefSnapshotPath(nodePath: string): string {
return `${getRefFlowPath(nodePath)}/${MESH.CURRENT_SNAPSHOT_DIR}/`;
}

export function getCurrentRefDistPath(nodePath: string): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getCurrentRefSnapshotPath(nodePath)}${lastSegment}_${MESH.REF}_${MESH.CURRENT}.jsonld`;
}

export function getNextRefSnapshotPath(nodePath: string): string {
return `${getRefFlowPath(nodePath)}/${MESH.NEXT_SNAPSHOT_DIR}/`;
}

export function getNextRefDistPath(nodePath: string): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getNextRefSnapshotPath(nodePath)}${lastSegment}_${MESH.REF}_${MESH.NEXT}.jsonld`;
}

export function getVersionRefSnapshotPath(nodePath: string, version: number): string {
return `${getRefFlowPath(nodePath)}/${MESH.VERSION_SNAPSHOT_PREFIX}${version}/`;
}

export function getVersionRefDistPath(nodePath: string, version: number): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getVersionRefSnapshotPath(nodePath, version)}${lastSegment}_${MESH.REF}_${MESH.VERSION_SNAPSHOT_PREFIX}${version}.jsonld`;
}

// data
export function getDataFlowPath(nodePath: string): string {
return `${nodePath}/${MESH.DATA_FLOW_DIR}/`;
}

export function getCurrentDataSnapshotPath(nodePath: string): string {
return `${getDataFlowPath(nodePath)}/${MESH.CURRENT_SNAPSHOT_DIR}/`;
}

export function getCurrentDataDistPath(nodePath: string): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getCurrentDataSnapshotPath(nodePath)}${lastSegment}_${MESH.DATA}_${MESH.CURRENT}.jsonld`;
}

export function getNextDataSnapshotPath(nodePath: string): string {
return `${getDataFlowPath(nodePath)}/${MESH.NEXT_SNAPSHOT_DIR}/`;
}

export function getNextDataDistPath(nodePath: string): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getNextDataSnapshotPath(nodePath)}${lastSegment}_${MESH.DATA}_${MESH.NEXT}.jsonld`;
}

export function getVersionDataSnapshotPath(nodePath: string, version: number): string {
return `${getDataFlowPath(nodePath)}/${MESH.VERSION_SNAPSHOT_PREFIX}${version}/`;
}

export function getVersionDataDistPath(nodePath: string, version: number): string {
const lastSegment = getLastPathSegment(nodePath);
return `${getVersionDataSnapshotPath(nodePath, version)}${lastSegment}_${MESH.DATA}_${MESH.VERSION_SNAPSHOT_PREFIX}${version}.jsonld`;
}
48 changes: 27 additions & 21 deletions flow-core/src/utils/path-utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Utility functions for path handling in flow-core

import { normalize } from '../deps.ts';

/**
* Converts a node relative path to a meta relative path by prepending "../../"
* This is used to navigate from a node's directory to its meta directory.
Expand All @@ -10,34 +12,38 @@
export function convertNodeRelativePathToMetaRelativePath(nodeRelativePath: string): string {
return `../../${nodeRelativePath}`;
}

/**
* Normalizes a node path to ensure it does not start with a slash or "./"
* and uses consistent separators.
* Normalizes a folder path by ensuring it ends with a slash.
* If the path is empty, it returns "/".
*
* @param nodePath - The node path to normalize
* @returns The normalized node path
* @param folderPath - The folder path to normalize
* @returns The normalized folder path
*/
export function normalizeNodePath(nodePath: string): string {
if (!nodePath) return '';
let normalized = nodePath;
if (normalized.startsWith('/')) {
normalized = normalized.slice(1);
}
if (normalized.startsWith('./')) {
normalized = normalized.slice(2);
}
// Additional normalization can be added here if needed
return normalized;

export function normalizeFolderPath(folderPath: string): string {
if (!folderPath) return "/";
const path = normalize(folderPath);
return path.endsWith("/") ? path : path + "/";
}

/**
* Extracts the last segment of a node path.
* Safely extracts the last segment of a path.
* Removes trailing slashes, then returns the substring after the last slash.
* If no slash is present, returns the entire path.
*
* @param nodePath - The node path string
* @param path - The filesystem path string
* @returns The last segment of the path
*/
export function getLastSegment(nodePath: string): string {
const parts = nodePath.split('/');
return parts[parts.length - 1] || '';
export function getLastPathSegment(path: string): string {
if (!path) return path;
// Remove trailing slashes
let trimmedPath = path;
while (trimmedPath.endsWith('/')) {
trimmedPath = trimmedPath.slice(0, -1);
}
const lastSlashIndex = trimmedPath.lastIndexOf('/');
if (lastSlashIndex === -1) {
return trimmedPath;
}
return trimmedPath.substring(lastSlashIndex + 1);
}
4 changes: 2 additions & 2 deletions flow-service/src/config/loaders/jsonld-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import type { ServiceConfigInput, NodeConfigInput } from '../types.ts';
import { ConfigError } from '../types.ts';
import { handleCaughtError } from '../../utils/logger.ts';
import { getCurrentConfigDistPath } from '../../../../flow-core/src/mesh-constants.ts';
import { dirname, resolve } from 'https://deno.land/std@0.208.0/path/mod.ts';
import { getCurrentConfigDistPath } from '../../../../flow-core/src/utils/mesh-path-utils.ts';
import { dirname, resolve } from '../../../../flow-core/src/deps.ts';

/**
* Loads a service configuration from a JSON-LD file at the specified path.
Expand Down
10 changes: 6 additions & 4 deletions flow-service/src/routes/meshes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';
import { logger } from '../utils/logger.ts';
import { getMetaFlowPath, getNextMetaDistPath, getCurrentMetaDistPath, MESH, getHandlePath, getAssetsPath } from '../../../flow-core/src/mesh-constants.ts';
import { join, dirname } from 'jsr:@std/path';
import { existsSync } from "https://deno.land/std@0.224.0/fs/mod.ts";
import { getMetaFlowPath, getNextMetaDistPath, getCurrentMetaDistPath, getHandlePath, getAssetsPath } from '../../../flow-core/src/utils/mesh-path-utils.ts';
import { normalizeFolderPath } from '../../../flow-core/src/utils/path-utils.ts';
import { MESH } from '../../../flow-core/src/mesh-constants.ts';
import { join, dirname, existsSync } from '../../../flow-core/src/deps.ts';
import { ServiceConfigAccessor } from '../config/index.ts';
import { composeMetadataContent } from '../services/metadata-composer.ts';
import { initializeMeshRegistry } from '../utils/mesh-utils.ts';
Expand Down Expand Up @@ -120,7 +121,8 @@ export const createMeshesRoutes = (config: ServiceConfigAccessor): OpenAPIHono =

meshes.openapi(registerMeshRoute, async (c) => {
const { name, parentPath } = c.req.valid('json');
const path = join(parentPath, name);
const normalizedParentPath = normalizeFolderPath(parentPath);
const path = join(normalizedParentPath, name);

if (meshRegistry[name]) {
return c.json({
Expand Down
Loading