36 | {maze.map((row, y) => (
37 |
38 | {row.map((_, x) => (
39 |
onCellClick(x, y)}
44 | />
45 | ))}
46 |
47 | ))}
48 |
49 | );
50 | };
51 |
--------------------------------------------------------------------------------
/sample_project/typescript/src/InfoPanel.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Node } from './node';
3 |
4 | interface InfoPanelProps {
5 | path: Node[] | null;
6 | }
7 |
8 | export const InfoPanel: React.FC
= ({ path }) => {
9 | return (
10 |
11 |
12 | Click cells to toggle walls. Green = Start, Red = End, Blue = Path
13 |
14 | {path && (
15 |
16 | Path length: {path.length} steps
17 |
18 | Total cost: {path[path.length - 1].g.toFixed(2)}
19 |
20 | )}
21 |
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/sample_project/typescript/src/PathfinderDisplay.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Node } from './node';
3 | import { AStar } from './astar';
4 | import { Grid } from './types';
5 | import { GridDisplay } from './GridDisplay';
6 | import { Controls } from './Controls';
7 | import { InfoPanel } from './InfoPanel';
8 |
9 | interface PathfinderDisplayProps {
10 | initialMaze?: Grid;
11 | start?: { x: number; y: number };
12 | end?: { x: number; y: number };
13 | allowDiagonal?: boolean;
14 | }
15 |
16 | export const PathfinderDisplay: React.FC = ({
17 | initialMaze = [
18 | [0, 0, 0, 0, 0, 0, 0, 0],
19 | [0, 0, 0, 0, 0, 0, 0, 0],
20 | [0, 0, 0, 100, 100, 100, 0, 0],
21 | [0, 0, 0, 0, 0, 100, 0, 0],
22 | [0, 0, 100, 0, 0, 100, 0, 0],
23 | [0, 0, 100, 0, 0, 100, 0, 0],
24 | [0, 0, 100, 100, 100, 100, 0, 0],
25 | [0, 0, 0, 0, 0, 0, 0, 0],
26 | ],
27 | start = { x: 0, y: 0 },
28 | end = { x: 7, y: 7 },
29 | allowDiagonal = true,
30 | }) => {
31 | const [maze, setMaze] = useState(initialMaze);
32 | const [path, setPath] = useState(null);
33 | const [isAnimating, setIsAnimating] = useState(false);
34 | const [currentStep, setCurrentStep] = useState(0);
35 |
36 | const findPath = () => {
37 | const astar = new AStar(maze, start.x, start.y, allowDiagonal);
38 | const newPath = astar.findPathTo(end.x, end.y);
39 | setPath(newPath);
40 | setCurrentStep(0);
41 | setIsAnimating(true);
42 | };
43 |
44 | useEffect(() => {
45 | if (isAnimating && path && currentStep < path.length) {
46 | const timer = setTimeout(() => {
47 | setCurrentStep(prev => prev + 1);
48 | }, 500);
49 | return () => clearTimeout(timer);
50 | }
51 | if (currentStep >= (path?.length ?? 0)) {
52 | setIsAnimating(false);
53 | }
54 | }, [isAnimating, currentStep, path]);
55 |
56 | const toggleCell = (x: number, y: number) => {
57 | if ((x === start.x && y === start.y) || (x === end.x && y === end.y)) return;
58 |
59 | const newMaze = maze.map(row => [...row]);
60 | newMaze[y][x] = newMaze[y][x] === 100 ? 0 : 100;
61 | setMaze(newMaze);
62 | setPath(null);
63 | setCurrentStep(0);
64 | };
65 |
66 | const handleReset = () => {
67 | setMaze(initialMaze);
68 | setPath(null);
69 | setCurrentStep(0);
70 | };
71 |
72 | return (
73 |
74 |
79 |
80 |
89 |
90 |
91 |
92 | );
93 | };
94 |
--------------------------------------------------------------------------------
/sample_project/typescript/src/astar.ts:
--------------------------------------------------------------------------------
1 | import { Node } from './node';
2 | import { Grid, Point } from './types';
3 |
4 | // Interface definition
5 | interface IAStarPathfinder {
6 | findPathTo(xend: number, yend: number): Node[] | null;
7 | }
8 |
9 | export class AStar implements IAStarPathfinder {
10 | private open: Node[] = [];
11 | private closed: Node[] = [];
12 | private path: Node[] = [];
13 | private now: Node;
14 |
15 | constructor(
16 | private maze: Grid,
17 | private xstart: number,
18 | private ystart: number,
19 | private diag: boolean
20 | ) {
21 | this.now = new Node(null, xstart, ystart, 0, 0);
22 | }
23 |
24 | // Arrow function method implementing interface method
25 | findPathTo = (xend: number, yend: number): Node[] | null => {
26 | this.closed.push(this.now);
27 | this.addNeighborsToOpenList(xend, yend);
28 | while (this.now.x !== xend || this.now.y !== yend) {
29 | if (this.open.length === 0) {
30 | return null;
31 | }
32 | this.now = this.open[0];
33 | this.open.splice(0, 1);
34 | this.closed.push(this.now);
35 | this.addNeighborsToOpenList(xend, yend);
36 | }
37 | this.path = [this.now];
38 | while (this.now.x !== this.xstart || this.now.y !== this.ystart) {
39 | this.now = this.now.parent!;
40 | this.path.unshift(this.now);
41 | }
42 | return this.path;
43 | };
44 |
45 | // Traditional method with function keyword
46 | private isInBounds(point: Point): boolean {
47 | return (
48 | point.x >= 0 &&
49 | point.x < this.maze[0].length &&
50 | point.y >= 0 &&
51 | point.y < this.maze.length
52 | );
53 | }
54 |
55 | // Arrow function as property
56 | private isWalkable = (point: Point): boolean => {
57 | return this.maze[point.y][point.x] !== -1;
58 | };
59 |
60 | // Method shorthand notation
61 | private addNeighborsToOpenList(xend: number, yend: number): void {
62 | for (let x = -1; x <= 1; x++) {
63 | for (let y = -1; y <= 1; y++) {
64 | if (!this.diag && x !== 0 && y !== 0) {
65 | continue;
66 | }
67 | const newPoint = {
68 | x: this.now.x + x,
69 | y: this.now.y + y
70 | };
71 | if (x === 0 && y === 0) continue;
72 | if (!this.isInBounds(newPoint)) continue;
73 | if (!this.isWalkable(newPoint)) continue;
74 | const node = new Node(
75 | this.now,
76 | newPoint.x,
77 | newPoint.y,
78 | this.now.g,
79 | this.distance(newPoint.x, newPoint.y, xend, yend)
80 | );
81 | if (
82 | this.findNeighborInList(this.open, node) ||
83 | this.findNeighborInList(this.closed, node)
84 | ) continue;
85 | node.g = node.parent!.g + 1;
86 | node.g += this.maze[newPoint.y][newPoint.x];
87 | this.open.push(node);
88 | }
89 | }
90 | this.open.sort((a, b) => a.f() - b.f());
91 | }
92 |
93 | // Arrow function with explicit parameter types
94 | private distance = (x1: number, y1: number, x2: number, y2: number): number => {
95 | return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
96 | };
97 |
98 | // Traditional function expression assigned to property
99 | private findNeighborInList = function(list: Node[], node: Node): boolean {
100 | return list.some(n => n.x === node.x && n.y === node.y);
101 | };
102 | }
103 |
--------------------------------------------------------------------------------
/sample_project/typescript/src/main.ts:
--------------------------------------------------------------------------------
1 | import { AStar } from './astar';
2 | import { PathVisualizer } from './visualization';
3 | import { Grid } from './types';
4 |
5 | // Arrow function for main
6 | const main = (): void => {
7 | const maze: Grid = [
8 | [0, 0, 0, 0, 0, 0, 0, 0],
9 | [0, 0, 0, 0, 0, 0, 0, 0],
10 | [0, 0, 0, 100, 100, 100, 0, 0],
11 | [0, 0, 0, 0, 0, 100, 0, 0],
12 | [0, 0, 100, 0, 0, 100, 0, 0],
13 | [0, 0, 100, 0, 0, 100, 0, 0],
14 | [0, 0, 100, 100, 100, 100, 0, 0],
15 | [0, 0, 0, 0, 0, 0, 0, 0],
16 | ];
17 |
18 | const astar = new AStar(maze, 0, 0, true);
19 | const path = astar.findPathTo(7, 7);
20 |
21 | if (path) {
22 | PathVisualizer.printPath(path);
23 | PathVisualizer.visualizePath(maze, path);
24 | } else {
25 | console.log('No path found!');
26 | }
27 | };
28 |
29 | // IIFE (Immediately Invoked Function Expression) with arrow function
30 | (() => {
31 | main();
32 | })();
33 |
34 | export { main };
35 |
--------------------------------------------------------------------------------
/sample_project/typescript/src/node.ts:
--------------------------------------------------------------------------------
1 | export class Node {
2 | constructor(
3 | public parent: Node | null,
4 | public x: number,
5 | public y: number,
6 | public g: number,
7 | public h: number
8 | ) {}
9 |
10 | // Arrow function for the getter
11 | f = (): number => this.g + this.h;
12 |
13 | // Alternative method using arrow function
14 | toString = (): string => `Node(${this.x}, ${this.y})`;
15 | }
16 |
--------------------------------------------------------------------------------
/sample_project/typescript/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface Point {
2 | x: number;
3 | y: number;
4 | }
5 |
6 | export type Grid = number[][];
7 |
--------------------------------------------------------------------------------
/sample_project/typescript/src/visualization.ts:
--------------------------------------------------------------------------------
1 | import { Node } from './node';
2 | import { Grid } from './types';
3 |
4 | export class PathVisualizer {
5 | // Traditional static method
6 | static visualizePath(maze: Grid, path: Node[]): void {
7 | const visualMaze = maze.map(row => [...row]);
8 |
9 | // Arrow function in forEach
10 | path.forEach((node): void => {
11 | visualMaze[node.y][node.x] = -1;
12 | });
13 |
14 | console.log('\nPath visualization:');
15 | visualMaze.forEach(row => {
16 | console.log(row.map(cell => {
17 | if (cell === 0) return '_';
18 | if (cell === -1) return '*';
19 | return '#';
20 | }).join(''));
21 | });
22 |
23 | console.log(`\nTotal cost: ${path[path.length - 1].g.toFixed(2)}`);
24 | }
25 |
26 | // Arrow function static method
27 | static printPath = (path: Node[]): void => {
28 | console.log('Path coordinates:');
29 | path.forEach(node => {
30 | console.log(`[${node.x}, ${node.y}]`);
31 | });
32 | };
33 | }
34 |
--------------------------------------------------------------------------------
/sample_project/typescript/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "module": "commonjs",
5 | "strict": true,
6 | "esModuleInterop": true,
7 | "skipLibCheck": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "outDir": "./dist",
10 | "rootDir": "./src"
11 | },
12 | "include": [
13 | "src/**/*"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/scripts/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e # Exit immediately if a command exits with a non-zero status
4 |
5 | # Build the application using the build Dockerfile
6 | docker build -t lsproxy-dev lsproxy
7 |
8 | # Run the builder container to create the binary
9 | if ! docker run --rm -v "$(pwd)/lsproxy":/usr/src/app lsproxy-dev; then
10 | echo "Build failed. Exiting."
11 | exit 1
12 | fi
13 |
--------------------------------------------------------------------------------
/scripts/coverage_test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e # Exit immediately if a command exits with a non-zero status
4 |
5 | # Build the application using the build Dockerfile
6 | docker build -t lsproxy-dev lsproxy
7 |
8 | if ! docker run --rm -v "$(pwd)/lsproxy":/usr/src/app -v "$(pwd)":/mnt/lsproxy_root lsproxy-dev cargo llvm-cov --html; then
9 | echo "Tests failed. Exiting."
10 | exit 1
11 | fi
12 |
--------------------------------------------------------------------------------
/scripts/fmt.sh:
--------------------------------------------------------------------------------
1 | docker build -t lsproxy-dev lsproxy
2 | docker run --rm -v "$(pwd)/lsproxy":/usr/src/app lsproxy-dev cargo fmt
3 |
--------------------------------------------------------------------------------
/scripts/generate_jwt.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import jwt
4 | import os
5 | import time
6 | import argparse
7 | from datetime import datetime
8 |
9 | def generate_token(secret=None):
10 | # Get JWT secret from argument or environment variable
11 | jwt_secret = secret or os.getenv('JWT_SECRET')
12 | if not jwt_secret:
13 | print("Error: No JWT secret provided")
14 | print("Please either:")
15 | print(" 1. Set environment variable: export JWT_SECRET=your_secret_here")
16 | print(" 2. Provide secret as argument: ./generate_jwt.py --secret your_secret_here")
17 | return
18 |
19 | # Set expiration to 24 hours from now
20 | exp = int(time.time()) + 86400 # Current time + 24 hours
21 |
22 | # Create claims
23 | claims = {
24 | 'exp': exp
25 | }
26 |
27 | try:
28 | # Generate token
29 | token = jwt.encode(claims, jwt_secret, algorithm='HS256')
30 |
31 | # Print results
32 | print("\nGenerated JWT Token. To use in Swagger UI, copy this token and then enter it in the authorize field of the UI:")
33 | print(f"{token}\n")
34 | print("To use in API requests, add the Bearer prefix:")
35 | print(f"Bearer {token}\n")
36 |
37 | print("Token will expire at:",
38 | datetime.fromtimestamp(exp).strftime('%Y-%m-%d %H:%M:%S'), "(in 24 hours)\n")
39 |
40 | except Exception as e:
41 | print(f"Error generating token: {e}")
42 |
43 | if __name__ == "__main__":
44 | parser = argparse.ArgumentParser(description='Generate JWT token')
45 | parser.add_argument('--secret', type=str, help='JWT secret key')
46 | args = parser.parse_args()
47 |
48 | generate_token(args.secret)
49 |
--------------------------------------------------------------------------------
/scripts/generate_spec.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e # Exit immediately if a command exits with a non-zero status
4 |
5 | ./scripts/build.sh
6 |
7 | # Run the application to generate the OpenAPI spec
8 | docker run --name temp_lsp_box -v "$(pwd)/lsproxy/target/release":/usr/src/app lsproxy-dev ./lsproxy -w
9 |
10 | # Copy the generated OpenAPI spec from the container to the host
11 | docker cp temp_lsp_box:/usr/src/app/openapi.json ./openapi.json
12 |
13 | # Remove the temporary container
14 | docker rm temp_lsp_box
15 |
16 | echo "OpenAPI specification has been generated and saved as openapi.json"
17 |
--------------------------------------------------------------------------------
/scripts/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e # Exit immediately if a command exits with a non-zero status
3 |
4 | # Color definitions
5 | GREEN='\033[0;32m'
6 | BLUE='\033[0;34m'
7 | YELLOW='\033[1;33m'
8 | NC='\033[0m' # No Color
9 |
10 | # Help function
11 | print_usage() {
12 | echo -e "${BLUE}Usage: $0 [--no-auth] ${NC}"
13 | echo -e " --no-auth : Disable authentication (sets USE_AUTH=false)"
14 | echo -e " workspace_path: Path to the workspace directory"
15 | }
16 |
17 | # Parse command line arguments
18 | WORKSPACE_PATH=""
19 | USE_AUTH=true
20 |
21 | while [[ $# -gt 0 ]]; do
22 | case $1 in
23 | --no-auth)
24 | USE_AUTH=false
25 | shift
26 | ;;
27 | -h|--help)
28 | print_usage
29 | exit 0
30 | ;;
31 | *)
32 | if [ -z "$WORKSPACE_PATH" ]; then
33 | WORKSPACE_PATH="$1"
34 | else
35 | echo -e "${YELLOW}Warning: Unexpected argument: $1${NC}"
36 | fi
37 | shift
38 | ;;
39 | esac
40 | done
41 |
42 | # Check if workspace path is provided
43 | if [ -z "$WORKSPACE_PATH" ]; then
44 | echo -e "${YELLOW}Error: Workspace path is required${NC}"
45 | print_usage
46 | exit 1
47 | fi
48 |
49 | if [ "$USE_AUTH" = true ]; then
50 | # Generate JWT token for Swagger login
51 | echo -e "${BLUE}Generating JWT token for Swagger UI login...${NC}"
52 | JWT_SECRET=test_secret ./scripts/generate_jwt.py
53 | echo -e "${YELLOW}Note: To disable authentication, you can use the --no-auth flag${NC}"
54 |
55 | # Ask for confirmation to continue - fixed syntax
56 | echo -e "${GREEN}Token has been generated. Press Enter to continue with application startup${NC}"
57 | read -p "(Ctrl+C to cancel)..."
58 |
59 | AUTH_ENV="-e JWT_SECRET=test_secret"
60 | else
61 | echo -e "${BLUE}Running in no-auth mode...${NC}"
62 | AUTH_ENV="-e USE_AUTH=false"
63 | fi
64 |
65 | echo -e "${BLUE}Starting application...${NC}"
66 |
67 | # Run the build
68 | ./scripts/build.sh
69 |
70 | # Run the application
71 | docker run --rm -p 4444:4444 \
72 | -v "$WORKSPACE_PATH:/mnt/workspace" \
73 | $AUTH_ENV \
74 | -v "$(pwd)/lsproxy/target/release":/usr/src/app \
75 | lsproxy-dev ./lsproxy
76 |
--------------------------------------------------------------------------------
/scripts/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e # Exit immediately if a command exits with a non-zero status
4 |
5 | # Build the application using the build Dockerfile
6 | docker build -t lsproxy-dev lsproxy
7 |
8 | if ! docker run --rm -v "$(pwd)/lsproxy":/usr/src/app -v "$(pwd)":/mnt/lsproxy_root lsproxy-dev cargo test $@; then
9 | echo "Tests failed. Exiting."
10 | exit 1
11 | fi
12 |
--------------------------------------------------------------------------------