kempo-server 1.7.10 → 1.7.12
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/dist/findFile.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import path from"path";export default(files,rootPath,requestPath,method,log)=>{log(`Finding file for: ${method} ${requestPath}`,3);
|
|
1
|
+
import path from"path";export default(files,rootPath,requestPath,method,log)=>{log(`Finding file for: ${method} ${requestPath}`,3);let normalizeRequestPath=requestPath.startsWith("/")?requestPath.slice(1):requestPath;normalizeRequestPath.endsWith("/")&&normalizeRequestPath.length>0&&(normalizeRequestPath=normalizeRequestPath.slice(0,-1));const requestSegments=normalizeRequestPath?normalizeRequestPath.split("/"):[];log(`Normalized request path: ${normalizeRequestPath}`,4),log(`Request segments: [${requestSegments.join(", ")}]`,4);const isDynamicSegment=segment=>segment.startsWith("[")&&segment.endsWith("]"),getParamName=segment=>segment.slice(1,-1),getRelativePath=filePath=>path.relative(rootPath,filePath).replace(/\\/g,"/"),exactMatch=files.find(file=>getRelativePath(file)===normalizeRequestPath);if(exactMatch)return log(`Found exact match: ${exactMatch}`,2),[exactMatch,{}];const isDirectoryRequest="/"===requestPath||requestPath.endsWith("/")||!path.extname(requestPath);if(isDirectoryRequest){log("Processing directory request",3);const dirPath=normalizeRequestPath||"",methodUpper=method.toUpperCase(),indexFiles=[`${methodUpper}.js`,`${methodUpper}.html`,"index.js","index.html"];log(`Looking for index files: [${indexFiles.join(", ")}]`,3);for(const indexFile of indexFiles){const indexPath=dirPath?`${dirPath}/${indexFile}`:indexFile,exactIndexMatch=files.find(file=>getRelativePath(file)===indexPath);if(exactIndexMatch)return log(`Found index file: ${exactIndexMatch}`,2),[exactIndexMatch,{}]}}log("Searching for dynamic routes...",3);const dynamicMatches=[];for(const file of files){const fileSegments=getRelativePath(file).split("/"),fileName=fileSegments[fileSegments.length-1],fileDirSegments=fileSegments.slice(0,-1);if(fileDirSegments.length!==requestSegments.length)continue;const pathParams={};let isMatch=!0;for(let i=0;i<fileDirSegments.length;i++){const fileSegment=fileDirSegments[i],requestSegment=requestSegments[i];if(isDynamicSegment(fileSegment)){const paramName=getParamName(fileSegment);pathParams[paramName]=requestSegment,log(`Dynamic match: [${paramName}] = ${requestSegment}`,4)}else if(fileSegment!==requestSegment){isMatch=!1;break}}if(isMatch)if(isDirectoryRequest){const methodUpper=method.toUpperCase(),priority=[`${methodUpper}.js`,`${methodUpper}.html`,"index.js","index.html"].indexOf(fileName);-1!==priority&&(log(`Found dynamic directory match: ${file} (priority: ${priority})`,3),dynamicMatches.push({file:file,pathParams:pathParams,priority:priority}))}else log(`Found dynamic file match: ${file}`,3),dynamicMatches.push({file:file,pathParams:pathParams,priority:0})}if(dynamicMatches.length>0){dynamicMatches.sort((a,b)=>a.priority-b.priority);const bestMatch=dynamicMatches[0];return log(`Best dynamic match: ${bestMatch.file} with params: ${JSON.stringify(bestMatch.pathParams)}`,2),[bestMatch.file,bestMatch.pathParams]}return log(`No file found for: ${requestPath}`,3),[!1,{}]};
|
package/package.json
CHANGED
package/src/findFile.js
CHANGED
|
@@ -4,7 +4,11 @@ export default (files, rootPath, requestPath, method, log) => {
|
|
|
4
4
|
log(`Finding file for: ${method} ${requestPath}`, 3);
|
|
5
5
|
|
|
6
6
|
// Normalize paths for comparison
|
|
7
|
-
|
|
7
|
+
let normalizeRequestPath = requestPath.startsWith('/') ? requestPath.slice(1) : requestPath;
|
|
8
|
+
// Remove trailing slash for directory path normalization (except for root)
|
|
9
|
+
if (normalizeRequestPath.endsWith('/') && normalizeRequestPath.length > 0) {
|
|
10
|
+
normalizeRequestPath = normalizeRequestPath.slice(0, -1);
|
|
11
|
+
}
|
|
8
12
|
const requestSegments = normalizeRequestPath ? normalizeRequestPath.split('/') : [];
|
|
9
13
|
|
|
10
14
|
log(`Normalized request path: ${normalizeRequestPath}`, 4);
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import findFile from '../src/findFile.js';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
'should resolve directory to index.html with trailing slash': async ({pass, fail, log}) => {
|
|
6
|
+
const root = path.join(process.cwd(), 'tests', 'test-server-root');
|
|
7
|
+
const files = [
|
|
8
|
+
path.join(root, 'sub-dir', 'index.html'),
|
|
9
|
+
path.join(root, 'index.html'),
|
|
10
|
+
path.join(root, 'hello.html')
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
log('Testing /sub-dir/ (with trailing slash)');
|
|
14
|
+
const [file, params] = findFile(files, root, '/sub-dir/', 'GET', () => {});
|
|
15
|
+
|
|
16
|
+
if (!file) {
|
|
17
|
+
return fail('No file found for /sub-dir/ request');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (path.basename(file) !== 'index.html') {
|
|
21
|
+
return fail(`Expected index.html, got ${path.basename(file)}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const relativePath = path.relative(root, file);
|
|
25
|
+
if (relativePath !== path.join('sub-dir', 'index.html')) {
|
|
26
|
+
return fail(`Expected sub-dir/index.html, got ${relativePath}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
pass('Directory with trailing slash correctly resolves to index.html');
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
'should resolve directory to index.html without trailing slash': async ({pass, fail, log}) => {
|
|
33
|
+
const root = path.join(process.cwd(), 'tests', 'test-server-root');
|
|
34
|
+
const files = [
|
|
35
|
+
path.join(root, 'sub-dir', 'index.html'),
|
|
36
|
+
path.join(root, 'index.html'),
|
|
37
|
+
path.join(root, 'hello.html')
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
log('Testing /sub-dir (without trailing slash)');
|
|
41
|
+
const [file, params] = findFile(files, root, '/sub-dir', 'GET', () => {});
|
|
42
|
+
|
|
43
|
+
if (!file) {
|
|
44
|
+
return fail('No file found for /sub-dir request');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (path.basename(file) !== 'index.html') {
|
|
48
|
+
return fail(`Expected index.html, got ${path.basename(file)}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const relativePath = path.relative(root, file);
|
|
52
|
+
if (relativePath !== path.join('sub-dir', 'index.html')) {
|
|
53
|
+
return fail(`Expected sub-dir/index.html, got ${relativePath}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pass('Directory without trailing slash correctly resolves to index.html');
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
'should prioritize GET.js over index.html for directory requests': async ({pass, fail, log}) => {
|
|
60
|
+
const root = path.join(process.cwd(), 'tests', 'test-server-root');
|
|
61
|
+
const files = [
|
|
62
|
+
path.join(root, 'sub-dir', 'GET.js'),
|
|
63
|
+
path.join(root, 'sub-dir', 'index.html'),
|
|
64
|
+
path.join(root, 'index.html')
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
log('Testing GET method priority with both GET.js and index.html present');
|
|
68
|
+
const [file, params] = findFile(files, root, '/sub-dir/', 'GET', () => {});
|
|
69
|
+
|
|
70
|
+
if (!file) {
|
|
71
|
+
return fail('No file found for /sub-dir/ request');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (path.basename(file) !== 'GET.js') {
|
|
75
|
+
return fail(`Expected GET.js to take priority, got ${path.basename(file)}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
pass('GET.js correctly takes priority over index.html');
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
'should resolve root directory to index.html': async ({pass, fail, log}) => {
|
|
82
|
+
const root = path.join(process.cwd(), 'tests', 'test-server-root');
|
|
83
|
+
const files = [
|
|
84
|
+
path.join(root, 'index.html'),
|
|
85
|
+
path.join(root, 'hello.html'),
|
|
86
|
+
path.join(root, 'sub-dir', 'index.html')
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
log('Testing root directory /');
|
|
90
|
+
const [file, params] = findFile(files, root, '/', 'GET', () => {});
|
|
91
|
+
|
|
92
|
+
if (!file) {
|
|
93
|
+
return fail('No file found for / request');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (path.basename(file) !== 'index.html') {
|
|
97
|
+
return fail(`Expected index.html, got ${path.basename(file)}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const relativePath = path.relative(root, file);
|
|
101
|
+
if (relativePath !== 'index.html') {
|
|
102
|
+
return fail(`Expected root index.html, got ${relativePath}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
pass('Root directory correctly resolves to index.html');
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
'should handle nested directory structures': async ({pass, fail, log}) => {
|
|
109
|
+
const root = path.join(process.cwd(), 'tests', 'test-server-root');
|
|
110
|
+
const files = [
|
|
111
|
+
path.join(root, 'docs', 'api', 'data.json'),
|
|
112
|
+
path.join(root, 'docs', 'src', 'components', 'Button.js'),
|
|
113
|
+
path.join(root, 'src', 'components', 'Button.js'),
|
|
114
|
+
path.join(root, 'src', 'components', 'index.html')
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
log('Testing nested directory /src/components/');
|
|
118
|
+
const [file, params] = findFile(files, root, '/src/components/', 'GET', () => {});
|
|
119
|
+
|
|
120
|
+
if (!file) {
|
|
121
|
+
return fail('No file found for /src/components/ request');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (path.basename(file) !== 'index.html') {
|
|
125
|
+
return fail(`Expected index.html, got ${path.basename(file)}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const relativePath = path.relative(root, file);
|
|
129
|
+
const expected = path.join('src', 'components', 'index.html');
|
|
130
|
+
if (relativePath !== expected) {
|
|
131
|
+
return fail(`Expected ${expected}, got ${relativePath}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
pass('Nested directory correctly resolves to index.html');
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
'should return false when no index file exists in directory': async ({pass, fail, log}) => {
|
|
138
|
+
const root = path.join(process.cwd(), 'tests', 'test-server-root');
|
|
139
|
+
const files = [
|
|
140
|
+
path.join(root, 'index.html'),
|
|
141
|
+
path.join(root, 'hello.html'),
|
|
142
|
+
path.join(root, 'b', '1.txt') // b directory has no index file
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
log('Testing directory with no index file /nonexistent/');
|
|
146
|
+
const [file, params] = findFile(files, root, '/nonexistent/', 'GET', () => {});
|
|
147
|
+
|
|
148
|
+
if (file !== false) {
|
|
149
|
+
return fail(`Expected false, got ${file}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
pass('Directory with no index file correctly returns false');
|
|
153
|
+
}
|
|
154
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Kempo UI</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>Kempo UI Test Page</h1>
|
|
10
|
+
<p>This is the index page for the sub-dir directory.</p>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|