gh-here 3.0.3 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +0 -0
- package/lib/constants.js +21 -16
- package/lib/content-search.js +212 -0
- package/lib/error-handler.js +39 -28
- package/lib/file-utils.js +438 -287
- package/lib/git.js +11 -55
- package/lib/gitignore.js +70 -41
- package/lib/renderers.js +17 -33
- package/lib/server.js +73 -196
- package/lib/symbol-parser.js +600 -0
- package/package.json +1 -1
- package/public/app.js +135 -68
- package/public/css/components/buttons.css +423 -0
- package/public/css/components/forms.css +171 -0
- package/public/css/components/modals.css +286 -0
- package/public/css/components/notifications.css +36 -0
- package/public/css/file-table.css +318 -0
- package/public/css/file-tree.css +269 -0
- package/public/css/file-viewer.css +1259 -0
- package/public/css/layout.css +372 -0
- package/public/css/main.css +35 -0
- package/public/css/reset.css +64 -0
- package/public/css/search.css +694 -0
- package/public/css/symbol-outline.css +279 -0
- package/public/css/variables.css +135 -0
- package/public/js/constants.js +50 -34
- package/public/js/content-search-handler.js +551 -0
- package/public/js/file-viewer.js +437 -0
- package/public/js/focus-mode.js +280 -0
- package/public/js/inline-search.js +659 -0
- package/public/js/modal-manager.js +14 -28
- package/public/js/symbol-outline.js +454 -0
- package/public/js/utils.js +152 -94
- package/.claude/settings.local.json +0 -30
- package/SAMPLE.md +0 -287
- package/lib/validation.js +0 -77
- package/public/app.js.backup +0 -1902
- package/public/highlight.css +0 -121
- package/public/js/draft-manager.js +0 -36
- package/public/js/editor-manager.js +0 -159
- package/public/styles.css +0 -2727
- package/test.js +0 -138
- package/tests/draftManager.test.js +0 -241
- package/tests/fileTypeDetection.test.js +0 -111
- package/tests/httpService.test.js +0 -268
- package/tests/languageDetection.test.js +0 -145
- package/tests/pathUtils.test.js +0 -136
package/public/js/utils.js
CHANGED
|
@@ -1,102 +1,92 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Utility functions for path and
|
|
2
|
+
* Utility functions for path manipulation, language detection, and HTML escaping
|
|
3
|
+
* @module utils
|
|
3
4
|
*/
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return currentUrl.searchParams.get('path') || '';
|
|
9
|
-
},
|
|
10
|
-
|
|
11
|
-
getParentPath(currentPath) {
|
|
12
|
-
if (!currentPath || currentPath === '') {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Language Map (alpha-sorted by key)
|
|
8
|
+
// ============================================================================
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
const LANGUAGE_MAP = {
|
|
11
|
+
bash: 'shell',
|
|
12
|
+
c: 'c',
|
|
13
|
+
cc: 'cpp',
|
|
14
|
+
clj: 'clojure',
|
|
15
|
+
cpp: 'cpp',
|
|
16
|
+
css: 'css',
|
|
17
|
+
cxx: 'cpp',
|
|
18
|
+
dart: 'dart',
|
|
19
|
+
fish: 'shell',
|
|
20
|
+
go: 'go',
|
|
21
|
+
groovy: 'groovy',
|
|
22
|
+
h: 'c',
|
|
23
|
+
hpp: 'cpp',
|
|
24
|
+
htm: 'html',
|
|
25
|
+
html: 'html',
|
|
26
|
+
java: 'java',
|
|
27
|
+
js: 'javascript',
|
|
28
|
+
json: 'json',
|
|
29
|
+
jsx: 'javascript',
|
|
30
|
+
kt: 'kotlin',
|
|
31
|
+
less: 'less',
|
|
32
|
+
log: 'plaintext',
|
|
33
|
+
lua: 'lua',
|
|
34
|
+
md: 'markdown',
|
|
35
|
+
mjs: 'javascript',
|
|
36
|
+
php: 'php',
|
|
37
|
+
pl: 'perl',
|
|
38
|
+
ps1: 'powershell',
|
|
39
|
+
py: 'python',
|
|
40
|
+
r: 'r',
|
|
41
|
+
rb: 'ruby',
|
|
42
|
+
rs: 'rust',
|
|
43
|
+
sass: 'sass',
|
|
44
|
+
scala: 'scala',
|
|
45
|
+
scss: 'scss',
|
|
46
|
+
sh: 'shell',
|
|
47
|
+
sql: 'sql',
|
|
48
|
+
swift: 'swift',
|
|
49
|
+
ts: 'typescript',
|
|
50
|
+
tsx: 'typescript',
|
|
51
|
+
txt: 'plaintext',
|
|
52
|
+
xml: 'xml',
|
|
53
|
+
yaml: 'yaml',
|
|
54
|
+
yml: 'yaml',
|
|
55
|
+
zsh: 'shell'
|
|
56
|
+
};
|
|
24
57
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
58
|
+
// ============================================================================
|
|
59
|
+
// HTML Utilities
|
|
60
|
+
// ============================================================================
|
|
28
61
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Escapes HTML special characters to prevent XSS attacks
|
|
64
|
+
* @param {string} text - Text to escape
|
|
65
|
+
* @returns {string} Escaped HTML string
|
|
66
|
+
*/
|
|
67
|
+
export function escapeHtml(text) {
|
|
68
|
+
if (typeof text !== 'string') return '';
|
|
69
|
+
const div = document.createElement('div');
|
|
70
|
+
div.textContent = text;
|
|
71
|
+
return div.innerHTML;
|
|
72
|
+
}
|
|
36
73
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return '';
|
|
41
|
-
}
|
|
42
|
-
return parts.slice(0, -1).join('/');
|
|
43
|
-
}
|
|
44
|
-
};
|
|
74
|
+
// ============================================================================
|
|
75
|
+
// Language Detection
|
|
76
|
+
// ============================================================================
|
|
45
77
|
|
|
46
78
|
/**
|
|
47
|
-
*
|
|
79
|
+
* Detects programming language from filename extension
|
|
80
|
+
* @param {string} filename - Filename to analyze
|
|
81
|
+
* @returns {string} Language identifier for syntax highlighting
|
|
48
82
|
*/
|
|
49
83
|
export function getLanguageFromExtension(filename) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
js: 'javascript',
|
|
53
|
-
mjs: 'javascript',
|
|
54
|
-
jsx: 'javascript',
|
|
55
|
-
ts: 'typescript',
|
|
56
|
-
tsx: 'typescript',
|
|
57
|
-
html: 'html',
|
|
58
|
-
htm: 'html',
|
|
59
|
-
css: 'css',
|
|
60
|
-
scss: 'scss',
|
|
61
|
-
sass: 'sass',
|
|
62
|
-
less: 'less',
|
|
63
|
-
json: 'json',
|
|
64
|
-
xml: 'xml',
|
|
65
|
-
yaml: 'yaml',
|
|
66
|
-
yml: 'yaml',
|
|
67
|
-
py: 'python',
|
|
68
|
-
java: 'java',
|
|
69
|
-
go: 'go',
|
|
70
|
-
rs: 'rust',
|
|
71
|
-
php: 'php',
|
|
72
|
-
rb: 'ruby',
|
|
73
|
-
swift: 'swift',
|
|
74
|
-
kt: 'kotlin',
|
|
75
|
-
dart: 'dart',
|
|
76
|
-
c: 'c',
|
|
77
|
-
cpp: 'cpp',
|
|
78
|
-
cc: 'cpp',
|
|
79
|
-
cxx: 'cpp',
|
|
80
|
-
h: 'c',
|
|
81
|
-
hpp: 'cpp',
|
|
82
|
-
sh: 'shell',
|
|
83
|
-
bash: 'shell',
|
|
84
|
-
zsh: 'shell',
|
|
85
|
-
fish: 'shell',
|
|
86
|
-
ps1: 'powershell',
|
|
87
|
-
sql: 'sql',
|
|
88
|
-
r: 'r',
|
|
89
|
-
scala: 'scala',
|
|
90
|
-
clj: 'clojure',
|
|
91
|
-
lua: 'lua',
|
|
92
|
-
pl: 'perl',
|
|
93
|
-
groovy: 'groovy',
|
|
94
|
-
md: 'markdown',
|
|
95
|
-
txt: 'plaintext',
|
|
96
|
-
log: 'plaintext'
|
|
97
|
-
};
|
|
98
|
-
|
|
84
|
+
if (!filename) return 'plaintext';
|
|
85
|
+
|
|
99
86
|
const basename = filename.toLowerCase();
|
|
87
|
+
const ext = filename.split('.').pop()?.toLowerCase();
|
|
88
|
+
|
|
89
|
+
// Special filenames
|
|
100
90
|
if (basename === 'dockerfile' || basename.startsWith('dockerfile.')) {
|
|
101
91
|
return 'dockerfile';
|
|
102
92
|
}
|
|
@@ -110,14 +100,82 @@ export function getLanguageFromExtension(filename) {
|
|
|
110
100
|
return 'json';
|
|
111
101
|
}
|
|
112
102
|
|
|
113
|
-
return
|
|
103
|
+
return LANGUAGE_MAP[ext] || 'plaintext';
|
|
114
104
|
}
|
|
115
105
|
|
|
106
|
+
// ============================================================================
|
|
107
|
+
// Path Utilities
|
|
108
|
+
// ============================================================================
|
|
109
|
+
|
|
116
110
|
/**
|
|
117
|
-
*
|
|
111
|
+
* Path manipulation utilities
|
|
118
112
|
*/
|
|
119
|
-
export
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
113
|
+
export const PathUtils = {
|
|
114
|
+
/**
|
|
115
|
+
* Builds a file path from directory and filename
|
|
116
|
+
* @param {string} currentPath - Current directory path
|
|
117
|
+
* @param {string} filename - Filename to append
|
|
118
|
+
* @returns {string} Combined file path
|
|
119
|
+
*/
|
|
120
|
+
buildFilePath(currentPath, filename) {
|
|
121
|
+
return currentPath ? `${currentPath}/${filename}` : filename;
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Builds a URL with path query parameter
|
|
126
|
+
* @param {string} basePath - Base URL path
|
|
127
|
+
* @param {string} targetPath - Target file/directory path
|
|
128
|
+
* @returns {string} URL with encoded path parameter
|
|
129
|
+
*/
|
|
130
|
+
buildPathUrl(basePath, targetPath) {
|
|
131
|
+
return targetPath ? `${basePath}?path=${encodeURIComponent(targetPath)}` : basePath;
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Gets the current path from URL query parameters
|
|
136
|
+
* @returns {string} Current path or empty string
|
|
137
|
+
*/
|
|
138
|
+
getCurrentPath() {
|
|
139
|
+
const currentUrl = new URL(window.location.href);
|
|
140
|
+
return currentUrl.searchParams.get('path') || '';
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Gets the directory portion of a file path
|
|
145
|
+
* @param {string} filePath - Full file path
|
|
146
|
+
* @returns {string} Directory path
|
|
147
|
+
*/
|
|
148
|
+
getDirectoryPath(filePath) {
|
|
149
|
+
const parts = filePath.split('/').filter(p => p);
|
|
150
|
+
if (parts.length <= 1) {
|
|
151
|
+
return '';
|
|
152
|
+
}
|
|
153
|
+
return parts.slice(0, -1).join('/');
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Gets the filename from a full path
|
|
158
|
+
* @param {string} filePath - Full file path
|
|
159
|
+
* @returns {string} Filename
|
|
160
|
+
*/
|
|
161
|
+
getFileName(filePath) {
|
|
162
|
+
return filePath.split('/').pop() || 'file.txt';
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Gets the parent directory path
|
|
167
|
+
* @param {string} currentPath - Current path
|
|
168
|
+
* @returns {string|null} Parent path or null if at root
|
|
169
|
+
*/
|
|
170
|
+
getParentPath(currentPath) {
|
|
171
|
+
if (!currentPath || currentPath === '') {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const pathParts = currentPath.split('/').filter(p => p);
|
|
175
|
+
if (pathParts.length === 0) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
pathParts.pop();
|
|
179
|
+
return pathParts.join('/');
|
|
180
|
+
}
|
|
181
|
+
};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(chmod:*)",
|
|
5
|
-
"Bash(npm install)",
|
|
6
|
-
"Bash(npm start)",
|
|
7
|
-
"Bash(pkill:*)",
|
|
8
|
-
"Bash(node:*)",
|
|
9
|
-
"Bash(curl:*)",
|
|
10
|
-
"Bash(npm install:*)",
|
|
11
|
-
"Bash(git init:*)",
|
|
12
|
-
"Bash(git add:*)",
|
|
13
|
-
"Bash(git commit:*)",
|
|
14
|
-
"Bash(git rm:*)",
|
|
15
|
-
"Bash(ssh:*)",
|
|
16
|
-
"Bash(git restore:*)",
|
|
17
|
-
"Bash(npx gh-here:*)",
|
|
18
|
-
"Bash(git checkout:*)",
|
|
19
|
-
"Bash(git push:*)",
|
|
20
|
-
"Bash(git pull:*)",
|
|
21
|
-
"Bash(npm publish:*)",
|
|
22
|
-
"Bash(timeout:*)",
|
|
23
|
-
"Bash(npm version:*)",
|
|
24
|
-
"Bash(gh release create:*)",
|
|
25
|
-
"Bash(tree:*)"
|
|
26
|
-
],
|
|
27
|
-
"deny": [],
|
|
28
|
-
"ask": []
|
|
29
|
-
}
|
|
30
|
-
}
|
package/SAMPLE.md
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
# Syntax Highlighting Test
|
|
2
|
-
|
|
3
|
-
This file contains code samples in various languages to test syntax highlighting in markdown rendering.
|
|
4
|
-
|
|
5
|
-
## JavaScript
|
|
6
|
-
|
|
7
|
-
```javascript
|
|
8
|
-
function greet(name) {
|
|
9
|
-
const message = `Hello, ${name}!`;
|
|
10
|
-
console.log(message);
|
|
11
|
-
return message;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
class Person {
|
|
15
|
-
constructor(name, age) {
|
|
16
|
-
this.name = name;
|
|
17
|
-
this.age = age;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
introduce() {
|
|
21
|
-
return `My name is ${this.name} and I'm ${this.age} years old.`;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Python
|
|
27
|
-
|
|
28
|
-
```python
|
|
29
|
-
def calculate_fibonacci(n):
|
|
30
|
-
"""Calculate the nth Fibonacci number."""
|
|
31
|
-
if n <= 1:
|
|
32
|
-
return n
|
|
33
|
-
return calculate_fibonacci(n - 1) + calculate_fibonacci(n - 2)
|
|
34
|
-
|
|
35
|
-
class Animal:
|
|
36
|
-
def __init__(self, name, species):
|
|
37
|
-
self.name = name
|
|
38
|
-
self.species = species
|
|
39
|
-
|
|
40
|
-
def make_sound(self):
|
|
41
|
-
return f"{self.name} the {self.species} makes a sound"
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Go
|
|
45
|
-
|
|
46
|
-
```go
|
|
47
|
-
package main
|
|
48
|
-
|
|
49
|
-
import (
|
|
50
|
-
"fmt"
|
|
51
|
-
"time"
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
type User struct {
|
|
55
|
-
Name string
|
|
56
|
-
Email string
|
|
57
|
-
CreatedAt time.Time
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
func (u *User) SendEmail(message string) error {
|
|
61
|
-
fmt.Printf("Sending email to %s: %s\n", u.Email, message)
|
|
62
|
-
return nil
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
func main() {
|
|
66
|
-
user := &User{
|
|
67
|
-
Name: "John Doe",
|
|
68
|
-
Email: "john@example.com",
|
|
69
|
-
CreatedAt: time.Now(),
|
|
70
|
-
}
|
|
71
|
-
user.SendEmail("Welcome!")
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Rust
|
|
76
|
-
|
|
77
|
-
```rust
|
|
78
|
-
use std::collections::HashMap;
|
|
79
|
-
|
|
80
|
-
fn main() {
|
|
81
|
-
let mut scores = HashMap::new();
|
|
82
|
-
scores.insert(String::from("Blue"), 10);
|
|
83
|
-
scores.insert(String::from("Red"), 50);
|
|
84
|
-
|
|
85
|
-
for (key, value) in &scores {
|
|
86
|
-
println!("{}: {}", key, value);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
struct Rectangle {
|
|
91
|
-
width: u32,
|
|
92
|
-
height: u32,
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
impl Rectangle {
|
|
96
|
-
fn area(&self) -> u32 {
|
|
97
|
-
self.width * self.height
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## TypeScript
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
interface User {
|
|
106
|
-
id: number;
|
|
107
|
-
name: string;
|
|
108
|
-
email: string;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async function fetchUser(id: number): Promise<User> {
|
|
112
|
-
const response = await fetch(`/api/users/${id}`);
|
|
113
|
-
const data: User = await response.json();
|
|
114
|
-
return data;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
class UserService {
|
|
118
|
-
private users: Map<number, User> = new Map();
|
|
119
|
-
|
|
120
|
-
addUser(user: User): void {
|
|
121
|
-
this.users.set(user.id, user);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
getUser(id: number): User | undefined {
|
|
125
|
-
return this.users.get(id);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Bash
|
|
131
|
-
|
|
132
|
-
```bash
|
|
133
|
-
#!/bin/bash
|
|
134
|
-
|
|
135
|
-
# Function to backup files
|
|
136
|
-
backup_files() {
|
|
137
|
-
local source_dir=$1
|
|
138
|
-
local backup_dir=$2
|
|
139
|
-
|
|
140
|
-
if [ ! -d "$backup_dir" ]; then
|
|
141
|
-
mkdir -p "$backup_dir"
|
|
142
|
-
fi
|
|
143
|
-
|
|
144
|
-
tar -czf "$backup_dir/backup-$(date +%Y%m%d).tar.gz" "$source_dir"
|
|
145
|
-
echo "Backup completed successfully!"
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
backup_files "/home/user/documents" "/home/user/backups"
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## SQL
|
|
152
|
-
|
|
153
|
-
```sql
|
|
154
|
-
-- Create users table
|
|
155
|
-
CREATE TABLE users (
|
|
156
|
-
id SERIAL PRIMARY KEY,
|
|
157
|
-
username VARCHAR(50) UNIQUE NOT NULL,
|
|
158
|
-
email VARCHAR(100) UNIQUE NOT NULL,
|
|
159
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
-- Insert some data
|
|
163
|
-
INSERT INTO users (username, email) VALUES
|
|
164
|
-
('john_doe', 'john@example.com'),
|
|
165
|
-
('jane_smith', 'jane@example.com');
|
|
166
|
-
|
|
167
|
-
-- Query with JOIN
|
|
168
|
-
SELECT u.username, o.order_date, o.total
|
|
169
|
-
FROM users u
|
|
170
|
-
INNER JOIN orders o ON u.id = o.user_id
|
|
171
|
-
WHERE o.total > 100
|
|
172
|
-
ORDER BY o.order_date DESC;
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## JSON
|
|
176
|
-
|
|
177
|
-
```json
|
|
178
|
-
{
|
|
179
|
-
"name": "gh-here",
|
|
180
|
-
"version": "2.0.0",
|
|
181
|
-
"description": "A local GitHub-like file browser",
|
|
182
|
-
"dependencies": {
|
|
183
|
-
"express": "^4.18.2",
|
|
184
|
-
"highlight.js": "^11.9.0",
|
|
185
|
-
"marked": "^12.0.0"
|
|
186
|
-
},
|
|
187
|
-
"scripts": {
|
|
188
|
-
"start": "node bin/gh-here.js",
|
|
189
|
-
"test": "jest"
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## CSS
|
|
195
|
-
|
|
196
|
-
```css
|
|
197
|
-
:root {
|
|
198
|
-
--primary-color: #0366d6;
|
|
199
|
-
--background-color: #ffffff;
|
|
200
|
-
--text-color: #24292e;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
.container {
|
|
204
|
-
max-width: 1200px;
|
|
205
|
-
margin: 0 auto;
|
|
206
|
-
padding: 20px;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.button {
|
|
210
|
-
display: inline-block;
|
|
211
|
-
padding: 10px 20px;
|
|
212
|
-
background-color: var(--primary-color);
|
|
213
|
-
color: white;
|
|
214
|
-
border-radius: 5px;
|
|
215
|
-
transition: background-color 0.3s ease;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
.button:hover {
|
|
219
|
-
background-color: #0256c7;
|
|
220
|
-
cursor: pointer;
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
## HTML
|
|
225
|
-
|
|
226
|
-
```html
|
|
227
|
-
<!DOCTYPE html>
|
|
228
|
-
<html lang="en">
|
|
229
|
-
<head>
|
|
230
|
-
<meta charset="UTF-8">
|
|
231
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
232
|
-
<title>Sample Page</title>
|
|
233
|
-
<link rel="stylesheet" href="styles.css">
|
|
234
|
-
</head>
|
|
235
|
-
<body>
|
|
236
|
-
<header>
|
|
237
|
-
<h1>Welcome to My Site</h1>
|
|
238
|
-
<nav>
|
|
239
|
-
<ul>
|
|
240
|
-
<li><a href="#home">Home</a></li>
|
|
241
|
-
<li><a href="#about">About</a></li>
|
|
242
|
-
<li><a href="#contact">Contact</a></li>
|
|
243
|
-
</ul>
|
|
244
|
-
</nav>
|
|
245
|
-
</header>
|
|
246
|
-
<main>
|
|
247
|
-
<p>This is the main content area.</p>
|
|
248
|
-
</main>
|
|
249
|
-
<script src="script.js"></script>
|
|
250
|
-
</body>
|
|
251
|
-
</html>
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
## Java
|
|
255
|
-
|
|
256
|
-
```java
|
|
257
|
-
import java.util.ArrayList;
|
|
258
|
-
import java.util.List;
|
|
259
|
-
|
|
260
|
-
public class BankAccount {
|
|
261
|
-
private String accountNumber;
|
|
262
|
-
private double balance;
|
|
263
|
-
private List<Transaction> transactions;
|
|
264
|
-
|
|
265
|
-
public BankAccount(String accountNumber, double initialBalance) {
|
|
266
|
-
this.accountNumber = accountNumber;
|
|
267
|
-
this.balance = initialBalance;
|
|
268
|
-
this.transactions = new ArrayList<>();
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
public void deposit(double amount) {
|
|
272
|
-
if (amount > 0) {
|
|
273
|
-
balance += amount;
|
|
274
|
-
transactions.add(new Transaction("DEPOSIT", amount));
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
public boolean withdraw(double amount) {
|
|
279
|
-
if (amount > 0 && balance >= amount) {
|
|
280
|
-
balance -= amount;
|
|
281
|
-
transactions.add(new Transaction("WITHDRAWAL", amount));
|
|
282
|
-
return true;
|
|
283
|
-
}
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
```
|
package/lib/validation.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Input validation and security utilities
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const path = require('path');
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Validates that a path is within the allowed working directory
|
|
9
|
-
* Prevents path traversal attacks
|
|
10
|
-
*/
|
|
11
|
-
function validatePath(requestPath, workingDir) {
|
|
12
|
-
const fullPath = path.resolve(path.join(workingDir, requestPath || ''));
|
|
13
|
-
return fullPath.startsWith(workingDir);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Sanitizes file paths to prevent injection
|
|
18
|
-
*/
|
|
19
|
-
function sanitizePath(filePath) {
|
|
20
|
-
if (!filePath) {
|
|
21
|
-
return '';
|
|
22
|
-
}
|
|
23
|
-
return filePath.replace(/\.\./g, '').replace(/[<>:"|?*]/g, '');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Validates commit message
|
|
28
|
-
*/
|
|
29
|
-
function validateCommitMessage(message) {
|
|
30
|
-
if (!message || typeof message !== 'string') {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
return message.trim().length > 0 && message.trim().length <= 5000;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Validates filename
|
|
38
|
-
*/
|
|
39
|
-
function validateFilename(filename) {
|
|
40
|
-
if (!filename || typeof filename !== 'string') {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const sanitized = filename.trim();
|
|
45
|
-
|
|
46
|
-
if (sanitized.length === 0 || sanitized.length > 255) {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const invalidChars = /[<>:"|?*\x00-\x1F]/;
|
|
51
|
-
if (invalidChars.test(sanitized)) {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Validates an array of file paths
|
|
60
|
-
*/
|
|
61
|
-
function validateFilePaths(files) {
|
|
62
|
-
if (!Array.isArray(files) || files.length === 0) {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return files.every(file => {
|
|
67
|
-
return typeof file === 'string' && file.trim().length > 0;
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
module.exports = {
|
|
72
|
-
validatePath,
|
|
73
|
-
sanitizePath,
|
|
74
|
-
validateCommitMessage,
|
|
75
|
-
validateFilename,
|
|
76
|
-
validateFilePaths
|
|
77
|
-
};
|