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
60 changes: 30 additions & 30 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"request": "launch",
"name": "Debug Service (Prod)",
"type": "node",
"program": "${workspaceFolder}/semantic-flow/flow-service/main.ts",
"cwd": "${workspaceFolder}/semantic-flow/flow-service/",
"env": {},
"runtimeExecutable": "C:\\Users\\drich\\.deno\\bin\\deno.EXE",
"runtimeArgs": [
"run",
"--watch",
"--env-file"
]
},
{
"name": "Attach Service",
"type": "node",
"request": "attach",
"port": 9229,
"address": "127.0.0.1",
"localRoot": "${workspaceFolder}",
"remoteRoot": "${workspaceFolder}",
"skipFiles": ["<node_internals>/**"]
}
]
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"request": "launch",
"name": "Debug Service (Prod)",
"type": "node",
"program": "${workspaceFolder}/flow-service/main.ts",
"cwd": "${workspaceFolder}/flow-service/",
"env": {},
"runtimeExecutable": "deno",
"runtimeArgs": [
"run",
"--watch",
"--env-file"
]
},
{
"name": "Attach Service",
"type": "node",
"request": "attach",
"port": 9229,
"address": "127.0.0.1",
"localRoot": "${workspaceFolder}",
"remoteRoot": "${workspaceFolder}",
"skipFiles": ["<node_internals>/**"]
}
]
}
126 changes: 125 additions & 1 deletion deno.lock

Large diffs are not rendered by default.

184 changes: 170 additions & 14 deletions flow-core/src/mesh-constants.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,45 @@
// flow-core/src/constants.ts
export const MESH_CONSTANTS = {
// Flow directory names
CONFIG_FLOW_DIR: "_config-flow",
META_FLOW_DIR: "_meta-flow",
REFERENCE_FLOW_DIR: "_ref-flow",
DATA_FLOW_DIR: "_data-flow",
const CONFIG = "config";
const META = "meta";
const REF = "ref";
const DATA = "data";

const NEXT = "next";
const CURRENT = "current";


export const MESH = {
// Flow slugs
CONFIG,
META,
REF,
DATA,
NEXT,
CURRENT,

// flow folders

CONFIG_FLOW_DIR: "_" + CONFIG + "-flow",
META_FLOW_DIR: "_" + META + "-flow",
REF_FLOW_DIR: "_" + REF + "-flow",
DATA_FLOW_DIR: "_" + DATA + "-flow",

NEXT_SNAPSHOT_DIR: "_" + NEXT,
CURRENT_SNAPSHOT_DIR: "_" + CURRENT,
VERSION_SNAPSHOT_PREFIX: "_v",

// Other element directory names
HANDLE_DIR: "_handle",
ASSETS_COMPONENT_DIR: "_assets",
NEXT_SNAPSHOT_DIR: "_next",
CURRENT_SNAPSHOT_DIR: "_current",
VERSION_PREFIX: "_v",
ASSETS_DIR: "_assets",

// System files
CONFIG_FILE: "flow-config.jsonld",
README_FILE: "README.md",
CHANGELOG_FILE: "CHANGELOG.md",

// Miscellaneous

API_IDENTIFIER_PATH_SEPARATOR: "~",
API_PORTAL_ROUTE: "/api-docs",

// Ontology namespaces
MESH_ONTOLOGY: "https://semantic-flow.github.io/ontology/mesh/",
NODE_ONTOLOGY: "https://semantic-flow.github.io/ontology/node/",
Expand All @@ -28,6 +50,140 @@ export const MESH_CONSTANTS = {
} as const;

// Usage throughout codebase
export function getNodeConfigPath(nodePath: string): string {
return `${nodePath}/${MESH_CONSTANTS.CONFIG_FLOW_DIR}/${MESH_CONSTANTS.CONFIG_FILE}`;


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`;
Comment on lines +73 to +74
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for nodePath extraction.

The lastIndexOf("/") operation could return -1 if no "/" is found, resulting in the entire path being used as the last segment. Consider adding validation or using a more robust path parsing approach.

Consider using a helper function to safely extract the last segment:

function getLastPathSegment(nodePath: string): string {
  const normalizedPath = nodePath.replace(/\/$/, ''); // Remove trailing slash
  const lastSlashIndex = normalizedPath.lastIndexOf("/");
  return lastSlashIndex === -1 ? normalizedPath : normalizedPath.substring(lastSlashIndex + 1);
}

Then update all the distribution path functions:

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

Also applies to: 82-83, 91-92, 105-106, 114-115, 123-124, 137-138, 146-147, 155-156, 169-170, 178-179, 187-188

🤖 Prompt for AI Agents
In flow-core/src/mesh-constants.ts around lines 73-74 and the other specified
pairs (82-83, 91-92, 105-106, 114-115, 123-124, 137-138, 146-147, 155-156,
169-170, 178-179, 187-188), the extraction of the last segment from nodePath
using lastIndexOf("/") can fail if "/" is not present, causing incorrect
results. Create a helper function that safely extracts the last path segment by
removing any trailing slash and checking if "/" exists before substring
extraction. Replace all direct substring calls with this helper function to
ensure robust and consistent path segment extraction.

}

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`;
}
43 changes: 43 additions & 0 deletions flow-core/src/utils/path-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Utility functions for path handling in flow-core

/**
* 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.
*
* @param nodeRelativePath - The relative path of the node
* @returns The relative path to the meta directory
*/
export function convertNodeRelativePathToMetaRelativePath(nodeRelativePath: string): string {
return `../../${nodeRelativePath}`;
}
Comment on lines +10 to +12
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation for robustness.

The function lacks input validation and could produce malformed paths with invalid inputs. Consider validating the input parameter.

 export function convertNodeRelativePathToMetaRelativePath(nodeRelativePath: string): string {
+  if (!nodeRelativePath || typeof nodeRelativePath !== 'string') {
+    throw new Error('nodeRelativePath must be a non-empty string');
+  }
   return `../../${nodeRelativePath}`;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function convertNodeRelativePathToMetaRelativePath(nodeRelativePath: string): string {
return `../../${nodeRelativePath}`;
}
export function convertNodeRelativePathToMetaRelativePath(nodeRelativePath: string): string {
if (!nodeRelativePath || typeof nodeRelativePath !== 'string') {
throw new Error('nodeRelativePath must be a non-empty string');
}
return `../../${nodeRelativePath}`;
}
🤖 Prompt for AI Agents
In flow-core/src/utils/path-utils.ts around lines 10 to 12, the function
convertNodeRelativePathToMetaRelativePath lacks input validation, which may lead
to malformed paths if given invalid inputs. Add validation to check that
nodeRelativePath is a non-empty string and conforms to expected path format
before constructing the return value. If the input is invalid, handle it
appropriately, such as throwing an error or returning a default safe value.


/**
* Normalizes a node path to ensure it does not start with a slash or "./"
* and uses consistent separators.
*
* @param nodePath - The node path to normalize
* @returns The normalized node 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;
}

/**
* Extracts the last segment of a node path.
*
* @param nodePath - The node path string
* @returns The last segment of the path
*/
export function getLastSegment(nodePath: string): string {
const parts = nodePath.split('/');
return parts[parts.length - 1] || '';
}
Comment on lines +40 to +43
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add input validation and improve error handling.

The function lacks input validation and could throw errors with invalid inputs. Also consider the path separator assumption.

 export function getLastSegment(nodePath: string): string {
+  if (!nodePath || typeof nodePath !== 'string') {
+    return '';
+  }
   const parts = nodePath.split('/');
   return parts[parts.length - 1] || '';
 }
🤖 Prompt for AI Agents
In flow-core/src/utils/path-utils.ts around lines 40 to 43, the getLastSegment
function lacks input validation and assumes '/' as the path separator. Add
validation to check if nodePath is a non-empty string before processing. Handle
cases where nodePath is undefined, null, or not a string by returning an empty
string or throwing a controlled error. Consider making the path separator
configurable or detect it dynamically to support different environments.

7 changes: 4 additions & 3 deletions flow-service/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
"@sentry/deno": "npm:@sentry/deno@^8.0.0"
},
"tasks": {
"start": "deno run --allow-net --allow-env --allow-read --allow-write --env-file main.ts",
"dev": "deno run --allow-net --allow-env --allow-read --allow-write --env-file --watch main.ts",
"debug": "deno run --allow-net --allow-env --allow-read --allow-write --env-file --inspect-brk=0.0.0.0:9229 main.ts"
"start": "deno run --allow-net --allow-env --allow-read --allow-write=../meshes --env-file main.ts",
"dev": "deno run --allow-net --allow-env --allow-read --allow-write=../meshes --env-file --watch main.ts",
"debug": "deno run --allow-net --allow-env --allow-read --allow-write=../meshes --env-file --inspect-brk=0.0.0.0:9229 main.ts",
"test": "deno test --allow-net --allow-env --allow-read --allow-write=../meshes"
},
"compilerOptions": {
"jsx": "precompile",
Expand Down
Loading