@hkdigital/lib-sveltekit 0.1.46 → 0.1.47
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/util/string/array-path.d.ts +15 -0
- package/dist/util/string/array-path.js +75 -0
- package/dist/util/string/convert.d.ts +22 -0
- package/dist/util/string/convert.js +54 -0
- package/dist/util/string/fs.d.ts +55 -0
- package/dist/util/string/fs.js +226 -0
- package/dist/util/string/index.d.ts +5 -60
- package/dist/util/string/index.js +5 -184
- package/dist/util/string/interpolate.d.ts +22 -0
- package/dist/util/string/interpolate.js +61 -0
- package/dist/util/string/pad.d.ts +8 -0
- package/dist/util/string/pad.js +10 -0
- package/dist/util/sveltekit/route-folders/index.d.ts +8 -3
- package/dist/util/sveltekit/route-folders/index.js +36 -17
- package/package.json +1 -1
@@ -0,0 +1,15 @@
|
|
1
|
+
/**
|
2
|
+
* Convert a path string to an array path
|
3
|
+
* - The path string will be spit at the `pathSeparator` token
|
4
|
+
* - If the supplied path is already an array, the original array will
|
5
|
+
* be returned
|
6
|
+
*
|
7
|
+
* @param {string|string[]} path
|
8
|
+
* String or array path (e.g. "some.path.to")
|
9
|
+
*
|
10
|
+
* @param {string} [pathSeparator=PATH_SEPARATOR]
|
11
|
+
* A custom path separator to use instead of the default "."
|
12
|
+
*
|
13
|
+
* @returns {string} string path (e.g. "some.path.to")
|
14
|
+
*/
|
15
|
+
export function toStringPath(path: string | string[], pathSeparator?: string): string;
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import { PATH_SEPARATOR } from '../object/index.js';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Convert a path string to an array path
|
5
|
+
* - The path string will be spit at the `pathSeparator` token
|
6
|
+
* - If the supplied path is already an array, the original array will
|
7
|
+
* be returned
|
8
|
+
*
|
9
|
+
* @param {string|string[]} path
|
10
|
+
* String or array path (e.g. "some.path.to")
|
11
|
+
*
|
12
|
+
* @param {string} [pathSeparator=PATH_SEPARATOR]
|
13
|
+
* A custom path separator to use instead of the default "."
|
14
|
+
*
|
15
|
+
* @returns {string} string path (e.g. "some.path.to")
|
16
|
+
*/
|
17
|
+
export function toStringPath(path, pathSeparator = PATH_SEPARATOR) {
|
18
|
+
if (Array.isArray(path)) {
|
19
|
+
return path.join(pathSeparator);
|
20
|
+
} else if (typeof path === 'string') {
|
21
|
+
// path is already a string
|
22
|
+
return path;
|
23
|
+
} else {
|
24
|
+
throw new Error(
|
25
|
+
'Missing or invalid parameter [path] (expected string or array)'
|
26
|
+
);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
// -----------------------------------------------------------------------------
|
31
|
+
|
32
|
+
/**
|
33
|
+
* Make sure that the outputted path is an array path
|
34
|
+
* - The input value may be a array path
|
35
|
+
* - The input value may be a string path (no conversion needed)
|
36
|
+
*
|
37
|
+
* @param {string|string[]} path
|
38
|
+
*
|
39
|
+
* @returns {string[]} array path (list of strings)
|
40
|
+
*/
|
41
|
+
// export function fromPath( path )
|
42
|
+
// {
|
43
|
+
// if( typeof path === "string" )
|
44
|
+
// {
|
45
|
+
// return path;
|
46
|
+
// }
|
47
|
+
// else {
|
48
|
+
// expect.array( path,
|
49
|
+
// "Missing or invalid parameter [path] (expected string or string[])" );
|
50
|
+
|
51
|
+
// let strPath = proc.arrayToStringPathWeakMap.get( path );
|
52
|
+
|
53
|
+
// if( strPath )
|
54
|
+
// {
|
55
|
+
// // std.debug( "Using cached value", path );
|
56
|
+
// return strPath;
|
57
|
+
// }
|
58
|
+
|
59
|
+
// // Check array path
|
60
|
+
// for( let j = 0, n = path.length; j < n; j = j + 1 )
|
61
|
+
// {
|
62
|
+
// if( typeof path[j] !== "string" )
|
63
|
+
// {
|
64
|
+
// throw new Error("Invalid array path. Expected array of strings");
|
65
|
+
// }
|
66
|
+
// }
|
67
|
+
|
68
|
+
// strPath = path.join("/");
|
69
|
+
|
70
|
+
// proc.safeArrayPathsWeakMap.set( path, true );
|
71
|
+
// proc.arrayToStringPathWeakMap.set( path, strPath );
|
72
|
+
|
73
|
+
// return strPath;
|
74
|
+
// }
|
75
|
+
// }
|
@@ -0,0 +1,22 @@
|
|
1
|
+
/**
|
2
|
+
* Remove strange characters from a string and replace whitespace by
|
3
|
+
* dashes.
|
4
|
+
*
|
5
|
+
* @returns {string} string that can be used as uri
|
6
|
+
*/
|
7
|
+
export function toUriName(str: any): string;
|
8
|
+
/**
|
9
|
+
* Captizalize the first character of a string
|
10
|
+
*
|
11
|
+
* @param {string} str - Input string
|
12
|
+
*
|
13
|
+
* @returns {string} string with first letter capitalized
|
14
|
+
*/
|
15
|
+
export function capitalizeFirst(str: string): string;
|
16
|
+
/**
|
17
|
+
* Converts a kebab-case string to Title Case.
|
18
|
+
*
|
19
|
+
* @param {string} kebabString - The kebab-case string to convert
|
20
|
+
* @return {string} The converted Title Case string
|
21
|
+
*/
|
22
|
+
export function kebabToTitleCase(kebabString: string): string;
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import * as expect from '../expect/index.js';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Remove strange characters from a string and replace whitespace by
|
5
|
+
* dashes.
|
6
|
+
*
|
7
|
+
* @returns {string} string that can be used as uri
|
8
|
+
*/
|
9
|
+
export function toUriName(str) {
|
10
|
+
expect.string(str);
|
11
|
+
|
12
|
+
str = str.toLowerCase().replace(/[^a-z0-9]+/gi, '-');
|
13
|
+
|
14
|
+
// TODO: remove duplicate dashes
|
15
|
+
|
16
|
+
return str;
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Captizalize the first character of a string
|
21
|
+
*
|
22
|
+
* @param {string} str - Input string
|
23
|
+
*
|
24
|
+
* @returns {string} string with first letter capitalized
|
25
|
+
*/
|
26
|
+
export function capitalizeFirst(str) {
|
27
|
+
if (!str.length) {
|
28
|
+
return str;
|
29
|
+
}
|
30
|
+
|
31
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Converts a kebab-case string to Title Case.
|
36
|
+
*
|
37
|
+
* @param {string} kebabString - The kebab-case string to convert
|
38
|
+
* @return {string} The converted Title Case string
|
39
|
+
*/
|
40
|
+
export function kebabToTitleCase(kebabString) {
|
41
|
+
// Check if input is a string
|
42
|
+
if (typeof kebabString !== 'string') {
|
43
|
+
throw new Error('Input must be a string');
|
44
|
+
}
|
45
|
+
|
46
|
+
// Split the string by hyphens
|
47
|
+
return kebabString
|
48
|
+
.split('-')
|
49
|
+
.map((word) => {
|
50
|
+
// Capitalize the first letter of each word
|
51
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
52
|
+
})
|
53
|
+
.join(' ');
|
54
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
/**
|
2
|
+
* Path utilities for working with file and directory paths.
|
3
|
+
* Provides functions similar to Node.js path module but for browser and SvelteKit use.
|
4
|
+
*/
|
5
|
+
/**
|
6
|
+
* Extracts the filename from a path, with or without extension.
|
7
|
+
*
|
8
|
+
* @param {string} path - The path to extract the filename from
|
9
|
+
* @param {boolean} [includeExtension=true] - Whether to include the extension
|
10
|
+
* @return {string} The extracted filename
|
11
|
+
*/
|
12
|
+
export function basename(path: string, includeExtension?: boolean): string;
|
13
|
+
/**
|
14
|
+
* Extracts the extension from a filename.
|
15
|
+
*
|
16
|
+
* @param {string} path - The path to extract the extension from
|
17
|
+
* @param {boolean} [includeDot=false] - Whether to include the dot in the extension
|
18
|
+
* @return {string} The extracted extension
|
19
|
+
*/
|
20
|
+
export function extname(path: string, includeDot?: boolean): string;
|
21
|
+
/**
|
22
|
+
* Extracts the directory name from a path.
|
23
|
+
*
|
24
|
+
* @param {string} path - The path to extract the directory name from
|
25
|
+
* @return {string} The extracted directory name
|
26
|
+
*/
|
27
|
+
export function dirname(path: string): string;
|
28
|
+
/**
|
29
|
+
* Joins path segments with the appropriate separator.
|
30
|
+
*
|
31
|
+
* @param {...string} paths - The path segments to join
|
32
|
+
* @return {string} The joined path
|
33
|
+
*/
|
34
|
+
export function join(...paths: string[]): string;
|
35
|
+
/**
|
36
|
+
* Normalizes a path by resolving '..' and '.' segments.
|
37
|
+
*
|
38
|
+
* @param {string} path - The path to normalize
|
39
|
+
* @return {string} The normalized path
|
40
|
+
*/
|
41
|
+
export function normalize(path: string): string;
|
42
|
+
/**
|
43
|
+
* Checks if a path is absolute.
|
44
|
+
*
|
45
|
+
* @param {string} path - The path to check
|
46
|
+
* @return {boolean} Whether the path is absolute
|
47
|
+
*/
|
48
|
+
export function isAbsolute(path: string): boolean;
|
49
|
+
/**
|
50
|
+
* Returns the path segments as an array.
|
51
|
+
*
|
52
|
+
* @param {string} path - The path to split
|
53
|
+
* @return {string[]} The path segments
|
54
|
+
*/
|
55
|
+
export function segments(path: string): string[];
|
@@ -0,0 +1,226 @@
|
|
1
|
+
/**
|
2
|
+
* Path utilities for working with file and directory paths.
|
3
|
+
* Provides functions similar to Node.js path module but for browser and SvelteKit use.
|
4
|
+
*/
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Extracts the filename from a path, with or without extension.
|
8
|
+
*
|
9
|
+
* @param {string} path - The path to extract the filename from
|
10
|
+
* @param {boolean} [includeExtension=true] - Whether to include the extension
|
11
|
+
* @return {string} The extracted filename
|
12
|
+
*/
|
13
|
+
export function basename(path, includeExtension = true) {
|
14
|
+
if (typeof path !== 'string') {
|
15
|
+
throw new Error('Path must be a string');
|
16
|
+
}
|
17
|
+
|
18
|
+
// Handle empty string
|
19
|
+
if (path === '') {
|
20
|
+
return '';
|
21
|
+
}
|
22
|
+
|
23
|
+
// Remove trailing slashes
|
24
|
+
path = path.replace(/\/+$/, '');
|
25
|
+
|
26
|
+
// Find the last occurrence of '/'
|
27
|
+
const lastSlashIndex = path.lastIndexOf('/');
|
28
|
+
|
29
|
+
// Get the full filename
|
30
|
+
const filename =
|
31
|
+
lastSlashIndex === -1 ? path : path.substring(lastSlashIndex + 1);
|
32
|
+
|
33
|
+
// Return the full filename if extension should be included
|
34
|
+
if (includeExtension) {
|
35
|
+
return filename;
|
36
|
+
}
|
37
|
+
|
38
|
+
// Otherwise, remove the extension
|
39
|
+
const lastDotIndex = filename.lastIndexOf('.');
|
40
|
+
|
41
|
+
// If no dot is found or dot is the first character (hidden file), return the filename
|
42
|
+
if (lastDotIndex <= 0) {
|
43
|
+
return filename;
|
44
|
+
}
|
45
|
+
|
46
|
+
// Return everything before the last dot
|
47
|
+
return filename.substring(0, lastDotIndex);
|
48
|
+
}
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Extracts the extension from a filename.
|
52
|
+
*
|
53
|
+
* @param {string} path - The path to extract the extension from
|
54
|
+
* @param {boolean} [includeDot=false] - Whether to include the dot in the extension
|
55
|
+
* @return {string} The extracted extension
|
56
|
+
*/
|
57
|
+
export function extname(path, includeDot = false) {
|
58
|
+
if (typeof path !== 'string') {
|
59
|
+
throw new Error('Path must be a string');
|
60
|
+
}
|
61
|
+
|
62
|
+
const filename = basename(path);
|
63
|
+
const lastDotIndex = filename.lastIndexOf('.');
|
64
|
+
|
65
|
+
// If no dot is found or dot is the first character (hidden file), return empty string
|
66
|
+
if (lastDotIndex <= 0) {
|
67
|
+
return '';
|
68
|
+
}
|
69
|
+
|
70
|
+
// Return the extension with or without the dot
|
71
|
+
return includeDot
|
72
|
+
? filename.substring(lastDotIndex)
|
73
|
+
: filename.substring(lastDotIndex + 1);
|
74
|
+
}
|
75
|
+
|
76
|
+
/**
|
77
|
+
* Extracts the directory name from a path.
|
78
|
+
*
|
79
|
+
* @param {string} path - The path to extract the directory name from
|
80
|
+
* @return {string} The extracted directory name
|
81
|
+
*/
|
82
|
+
export function dirname(path) {
|
83
|
+
if (typeof path !== 'string') {
|
84
|
+
throw new Error('Path must be a string');
|
85
|
+
}
|
86
|
+
|
87
|
+
// Handle empty string
|
88
|
+
if (path === '') {
|
89
|
+
return '.';
|
90
|
+
}
|
91
|
+
|
92
|
+
// Remove trailing slashes
|
93
|
+
path = path.replace(/\/+$/, '');
|
94
|
+
|
95
|
+
// Find the last occurrence of '/'
|
96
|
+
const lastSlashIndex = path.lastIndexOf('/');
|
97
|
+
|
98
|
+
// If no slash is found, return '.'
|
99
|
+
if (lastSlashIndex === -1) {
|
100
|
+
return '.';
|
101
|
+
}
|
102
|
+
|
103
|
+
// If slash is at the beginning, return '/'
|
104
|
+
if (lastSlashIndex === 0) {
|
105
|
+
return '/';
|
106
|
+
}
|
107
|
+
|
108
|
+
// Return everything before the last slash
|
109
|
+
return path.substring(0, lastSlashIndex);
|
110
|
+
}
|
111
|
+
|
112
|
+
/**
|
113
|
+
* Joins path segments with the appropriate separator.
|
114
|
+
*
|
115
|
+
* @param {...string} paths - The path segments to join
|
116
|
+
* @return {string} The joined path
|
117
|
+
*/
|
118
|
+
export function join(...paths) {
|
119
|
+
if (paths.length === 0) {
|
120
|
+
return '.';
|
121
|
+
}
|
122
|
+
|
123
|
+
return paths
|
124
|
+
.filter((segment) => typeof segment === 'string' && segment !== '')
|
125
|
+
.join('/')
|
126
|
+
.replace(/\/+/g, '/'); // Replace multiple consecutive slashes with a single one
|
127
|
+
}
|
128
|
+
|
129
|
+
/**
|
130
|
+
* Normalizes a path by resolving '..' and '.' segments.
|
131
|
+
*
|
132
|
+
* @param {string} path - The path to normalize
|
133
|
+
* @return {string} The normalized path
|
134
|
+
*/
|
135
|
+
export function normalize(path) {
|
136
|
+
if (typeof path !== 'string') {
|
137
|
+
throw new Error('Path must be a string');
|
138
|
+
}
|
139
|
+
|
140
|
+
// Replace backslashes with forward slashes
|
141
|
+
path = path.replace(/\\/g, '/');
|
142
|
+
|
143
|
+
// Handle empty string
|
144
|
+
if (path === '') {
|
145
|
+
return '.';
|
146
|
+
}
|
147
|
+
|
148
|
+
const isAbsolute = path.startsWith('/');
|
149
|
+
const trailingSlash = path.endsWith('/');
|
150
|
+
|
151
|
+
// Split path into segments
|
152
|
+
const segments = path.split('/').filter(Boolean);
|
153
|
+
const resultSegments = [];
|
154
|
+
|
155
|
+
for (const segment of segments) {
|
156
|
+
if (segment === '.') {
|
157
|
+
// Ignore current directory marker
|
158
|
+
continue;
|
159
|
+
} else if (segment === '..') {
|
160
|
+
// Go up one directory
|
161
|
+
if (
|
162
|
+
resultSegments.length > 0 &&
|
163
|
+
resultSegments[resultSegments.length - 1] !== '..'
|
164
|
+
) {
|
165
|
+
resultSegments.pop();
|
166
|
+
} else if (!isAbsolute) {
|
167
|
+
resultSegments.push('..');
|
168
|
+
}
|
169
|
+
} else {
|
170
|
+
// Add segment to result
|
171
|
+
resultSegments.push(segment);
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
// Handle empty result
|
176
|
+
if (resultSegments.length === 0) {
|
177
|
+
return isAbsolute ? '/' : '.';
|
178
|
+
}
|
179
|
+
|
180
|
+
// Join segments
|
181
|
+
let result = resultSegments.join('/');
|
182
|
+
|
183
|
+
// Add leading slash for absolute paths
|
184
|
+
if (isAbsolute) {
|
185
|
+
result = '/' + result;
|
186
|
+
}
|
187
|
+
|
188
|
+
// Add trailing slash if original path had one
|
189
|
+
if (trailingSlash && !result.endsWith('/')) {
|
190
|
+
result += '/';
|
191
|
+
}
|
192
|
+
|
193
|
+
return result;
|
194
|
+
}
|
195
|
+
|
196
|
+
/**
|
197
|
+
* Checks if a path is absolute.
|
198
|
+
*
|
199
|
+
* @param {string} path - The path to check
|
200
|
+
* @return {boolean} Whether the path is absolute
|
201
|
+
*/
|
202
|
+
export function isAbsolute(path) {
|
203
|
+
if (typeof path !== 'string') {
|
204
|
+
throw new Error('Path must be a string');
|
205
|
+
}
|
206
|
+
|
207
|
+
return path.startsWith('/');
|
208
|
+
}
|
209
|
+
|
210
|
+
/**
|
211
|
+
* Returns the path segments as an array.
|
212
|
+
*
|
213
|
+
* @param {string} path - The path to split
|
214
|
+
* @return {string[]} The path segments
|
215
|
+
*/
|
216
|
+
export function segments(path) {
|
217
|
+
if (typeof path !== 'string') {
|
218
|
+
throw new Error('Path must be a string');
|
219
|
+
}
|
220
|
+
|
221
|
+
// Normalize path first
|
222
|
+
const normalizedPath = normalize(path);
|
223
|
+
|
224
|
+
// Split path into segments
|
225
|
+
return normalizedPath.split('/').filter(Boolean);
|
226
|
+
}
|
@@ -1,60 +1,5 @@
|
|
1
|
-
|
2
|
-
*
|
3
|
-
*
|
4
|
-
*
|
5
|
-
*
|
6
|
-
* @returns {string} string with first letter capitalized
|
7
|
-
*/
|
8
|
-
export function capitalizeFirst(str: string): string;
|
9
|
-
/**
|
10
|
-
* Interpolate: substitute variables in a string
|
11
|
-
*
|
12
|
-
* - Uses mustache template style expression substitution:
|
13
|
-
* Variables and expressions are surrounded by {{...}}
|
14
|
-
*
|
15
|
-
* TODO: full mustache support, see https://github.com/janl/mustache.js
|
16
|
-
*
|
17
|
-
* --
|
18
|
-
*
|
19
|
-
* @eg const template = `Hello {{name}}`;
|
20
|
-
*
|
21
|
-
* --
|
22
|
-
*
|
23
|
-
* @param {string} template - Template string to interpolate
|
24
|
-
* @param {object} templateData - Template data to use for interpolation
|
25
|
-
*
|
26
|
-
* @returns {string} interpolated string
|
27
|
-
*/
|
28
|
-
export function interpolate(template: string, templateData: object, expressionRegexp?: RegExp): string;
|
29
|
-
/**
|
30
|
-
* Remove strange characters from a string and replace whitespace by
|
31
|
-
* dashes.
|
32
|
-
*
|
33
|
-
* @returns {string} string that can be used as uri
|
34
|
-
*/
|
35
|
-
export function toUriName(str: any): string;
|
36
|
-
/**
|
37
|
-
* Convert a path string to an array path
|
38
|
-
* - The path string will be spit at the `pathSeparator` token
|
39
|
-
* - If the supplied path is already an array, the original array will
|
40
|
-
* be returned
|
41
|
-
*
|
42
|
-
* @param {string|string[]} path
|
43
|
-
* String or array path (e.g. "some.path.to")
|
44
|
-
*
|
45
|
-
* @param {string} [pathSeparator=PATH_SEPARATOR]
|
46
|
-
* A custom path separator to use instead of the default "."
|
47
|
-
*
|
48
|
-
* @returns {string[]} array path (e.g. ["some", "path", "to"])
|
49
|
-
*/
|
50
|
-
export function toStringPath(path: string | string[], pathSeparator?: string): string[];
|
51
|
-
/**
|
52
|
-
* Prefix a numeric string with 0's
|
53
|
-
*
|
54
|
-
* @param {string|number} input
|
55
|
-
*
|
56
|
-
* @returns {string}
|
57
|
-
*/
|
58
|
-
export function padDigits(input: string | number, targetLength?: number, padString?: string): string;
|
59
|
-
export const RE_JS_EXPRESSION: RegExp;
|
60
|
-
export const RE_MUSTACHE: RegExp;
|
1
|
+
export * from "./array-path.js";
|
2
|
+
export * from "./convert.js";
|
3
|
+
export * from "./fs.js";
|
4
|
+
export * from "./interpolate.js";
|
5
|
+
export * from "./pad.js";
|
@@ -1,184 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
import { toArrayPath } from '../array/index.js';
|
8
|
-
|
9
|
-
/* ------------------------------------------------------------------ Exports */
|
10
|
-
|
11
|
-
export const RE_JS_EXPRESSION = /\$\{([^${}]*)\}/g;
|
12
|
-
export const RE_MUSTACHE = /\{\{([^{}]*)\}\}/g;
|
13
|
-
|
14
|
-
// -----------------------------------------------------------------------------
|
15
|
-
|
16
|
-
/**
|
17
|
-
* Captizalize the first character of a string
|
18
|
-
*
|
19
|
-
* @param {string} str - Input string
|
20
|
-
*
|
21
|
-
* @returns {string} string with first letter capitalized
|
22
|
-
*/
|
23
|
-
export function capitalizeFirst(str) {
|
24
|
-
if (!str.length) {
|
25
|
-
return str;
|
26
|
-
}
|
27
|
-
|
28
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
29
|
-
}
|
30
|
-
|
31
|
-
// -----------------------------------------------------------------------------
|
32
|
-
|
33
|
-
/**
|
34
|
-
* Interpolate: substitute variables in a string
|
35
|
-
*
|
36
|
-
* - Uses mustache template style expression substitution:
|
37
|
-
* Variables and expressions are surrounded by {{...}}
|
38
|
-
*
|
39
|
-
* TODO: full mustache support, see https://github.com/janl/mustache.js
|
40
|
-
*
|
41
|
-
* --
|
42
|
-
*
|
43
|
-
* @eg const template = `Hello {{name}}`;
|
44
|
-
*
|
45
|
-
* --
|
46
|
-
*
|
47
|
-
* @param {string} template - Template string to interpolate
|
48
|
-
* @param {object} templateData - Template data to use for interpolation
|
49
|
-
*
|
50
|
-
* @returns {string} interpolated string
|
51
|
-
*/
|
52
|
-
export function interpolate(template, templateData, expressionRegexp = RE_MUSTACHE) {
|
53
|
-
expect.string(template, 'Missing or invalid variable [template]');
|
54
|
-
|
55
|
-
expect.object(templateData, 'Missing or invalid variable [templateData]');
|
56
|
-
|
57
|
-
return template.replace(
|
58
|
-
expressionRegexp,
|
59
|
-
|
60
|
-
(match, expression) => {
|
61
|
-
const path = toArrayPath(expression);
|
62
|
-
|
63
|
-
const replacement = objectGet(templateData, path, undefined);
|
64
|
-
|
65
|
-
if (
|
66
|
-
typeof replacement !== 'string' &&
|
67
|
-
typeof replacement !== 'number' &&
|
68
|
-
typeof replacement !== 'boolean'
|
69
|
-
) {
|
70
|
-
throw new Error(
|
71
|
-
'Failed to interpolate template: Missing or invalid value for ' +
|
72
|
-
`expression [${expression}] (expected string, number or boolean)`
|
73
|
-
);
|
74
|
-
}
|
75
|
-
|
76
|
-
return replacement;
|
77
|
-
}
|
78
|
-
);
|
79
|
-
}
|
80
|
-
|
81
|
-
// -----------------------------------------------------------------------------
|
82
|
-
|
83
|
-
/**
|
84
|
-
* Remove strange characters from a string and replace whitespace by
|
85
|
-
* dashes.
|
86
|
-
*
|
87
|
-
* @returns {string} string that can be used as uri
|
88
|
-
*/
|
89
|
-
export function toUriName(str) {
|
90
|
-
expect.string(str, 'Missing or invalid variable [str]');
|
91
|
-
|
92
|
-
str = str.toLowerCase().replace(/[^a-z0-9]+/gi, '-');
|
93
|
-
|
94
|
-
// TODO: remove duplicate dashes
|
95
|
-
|
96
|
-
return str;
|
97
|
-
}
|
98
|
-
|
99
|
-
// -----------------------------------------------------------------------------
|
100
|
-
|
101
|
-
/**
|
102
|
-
* Convert a path string to an array path
|
103
|
-
* - The path string will be spit at the `pathSeparator` token
|
104
|
-
* - If the supplied path is already an array, the original array will
|
105
|
-
* be returned
|
106
|
-
*
|
107
|
-
* @param {string|string[]} path
|
108
|
-
* String or array path (e.g. "some.path.to")
|
109
|
-
*
|
110
|
-
* @param {string} [pathSeparator=PATH_SEPARATOR]
|
111
|
-
* A custom path separator to use instead of the default "."
|
112
|
-
*
|
113
|
-
* @returns {string[]} array path (e.g. ["some", "path", "to"])
|
114
|
-
*/
|
115
|
-
export function toStringPath(path, pathSeparator = PATH_SEPARATOR) {
|
116
|
-
if (Array.isArray(path)) {
|
117
|
-
return path.join(pathSeparator);
|
118
|
-
} else if (typeof path === 'string') {
|
119
|
-
// path is already a string
|
120
|
-
return path;
|
121
|
-
} else {
|
122
|
-
throw new Error('Missing or invalid parameter [path] (expected string or array)');
|
123
|
-
}
|
124
|
-
}
|
125
|
-
|
126
|
-
// -----------------------------------------------------------------------------
|
127
|
-
|
128
|
-
/**
|
129
|
-
* Prefix a numeric string with 0's
|
130
|
-
*
|
131
|
-
* @param {string|number} input
|
132
|
-
*
|
133
|
-
* @returns {string}
|
134
|
-
*/
|
135
|
-
export function padDigits(input, targetLength = 2, padString = '0') {
|
136
|
-
return ('' + input).padStart(targetLength, padString);
|
137
|
-
}
|
138
|
-
|
139
|
-
// -----------------------------------------------------------------------------
|
140
|
-
|
141
|
-
/**
|
142
|
-
* Make sure that the outputted path is an array path
|
143
|
-
* - The input value may be a array path
|
144
|
-
* - The input value may be a string path (no conversion needed)
|
145
|
-
*
|
146
|
-
* @param {string|string[]} path
|
147
|
-
*
|
148
|
-
* @returns {string[]} array path (list of strings)
|
149
|
-
*/
|
150
|
-
// export function fromPath( path )
|
151
|
-
// {
|
152
|
-
// if( typeof path === "string" )
|
153
|
-
// {
|
154
|
-
// return path;
|
155
|
-
// }
|
156
|
-
// else {
|
157
|
-
// expect.array( path,
|
158
|
-
// "Missing or invalid parameter [path] (expected string or string[])" );
|
159
|
-
|
160
|
-
// let strPath = proc.arrayToStringPathWeakMap.get( path );
|
161
|
-
|
162
|
-
// if( strPath )
|
163
|
-
// {
|
164
|
-
// // std.debug( "Using cached value", path );
|
165
|
-
// return strPath;
|
166
|
-
// }
|
167
|
-
|
168
|
-
// // Check array path
|
169
|
-
// for( let j = 0, n = path.length; j < n; j = j + 1 )
|
170
|
-
// {
|
171
|
-
// if( typeof path[j] !== "string" )
|
172
|
-
// {
|
173
|
-
// throw new Error("Invalid array path. Expected array of strings");
|
174
|
-
// }
|
175
|
-
// }
|
176
|
-
|
177
|
-
// strPath = path.join("/");
|
178
|
-
|
179
|
-
// proc.safeArrayPathsWeakMap.set( path, true );
|
180
|
-
// proc.arrayToStringPathWeakMap.set( path, strPath );
|
181
|
-
|
182
|
-
// return strPath;
|
183
|
-
// }
|
184
|
-
// }
|
1
|
+
export * from './array-path.js';
|
2
|
+
export * from './convert.js';
|
3
|
+
export * from './fs.js';
|
4
|
+
export * from './interpolate.js';
|
5
|
+
export * from './pad.js';
|
@@ -0,0 +1,22 @@
|
|
1
|
+
/**
|
2
|
+
* Interpolate: substitute variables in a string
|
3
|
+
*
|
4
|
+
* - Uses mustache template style expression substitution:
|
5
|
+
* Variables and expressions are surrounded by {{...}}
|
6
|
+
*
|
7
|
+
* TODO: full mustache support, see https://github.com/janl/mustache.js
|
8
|
+
*
|
9
|
+
* --
|
10
|
+
*
|
11
|
+
* @eg const template = `Hello {{name}}`;
|
12
|
+
*
|
13
|
+
* --
|
14
|
+
*
|
15
|
+
* @param {string} template - Template string to interpolate
|
16
|
+
* @param {object} templateData - Template data to use for interpolation
|
17
|
+
*
|
18
|
+
* @returns {string} interpolated string
|
19
|
+
*/
|
20
|
+
export function interpolate(template: string, templateData: object, expressionRegexp?: RegExp): string;
|
21
|
+
export const RE_JS_EXPRESSION: RegExp;
|
22
|
+
export const RE_MUSTACHE: RegExp;
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import * as expect from '../expect/index.js';
|
2
|
+
|
3
|
+
import { toArrayPath } from '../array/index.js';
|
4
|
+
|
5
|
+
import { objectGet, PATH_SEPARATOR } from '../object/index.js';
|
6
|
+
|
7
|
+
export const RE_JS_EXPRESSION = /\$\{([^${}]*)\}/g;
|
8
|
+
export const RE_MUSTACHE = /\{\{([^{}]*)\}\}/g;
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Interpolate: substitute variables in a string
|
12
|
+
*
|
13
|
+
* - Uses mustache template style expression substitution:
|
14
|
+
* Variables and expressions are surrounded by {{...}}
|
15
|
+
*
|
16
|
+
* TODO: full mustache support, see https://github.com/janl/mustache.js
|
17
|
+
*
|
18
|
+
* --
|
19
|
+
*
|
20
|
+
* @eg const template = `Hello {{name}}`;
|
21
|
+
*
|
22
|
+
* --
|
23
|
+
*
|
24
|
+
* @param {string} template - Template string to interpolate
|
25
|
+
* @param {object} templateData - Template data to use for interpolation
|
26
|
+
*
|
27
|
+
* @returns {string} interpolated string
|
28
|
+
*/
|
29
|
+
export function interpolate(
|
30
|
+
template,
|
31
|
+
templateData,
|
32
|
+
expressionRegexp = RE_MUSTACHE
|
33
|
+
) {
|
34
|
+
expect.string(template);
|
35
|
+
|
36
|
+
expect.object(templateData);
|
37
|
+
|
38
|
+
return template.replace(
|
39
|
+
expressionRegexp,
|
40
|
+
|
41
|
+
(match, expression) => {
|
42
|
+
const path = toArrayPath(expression);
|
43
|
+
|
44
|
+
/** @type {string} */
|
45
|
+
const replacement = objectGet(templateData, path, undefined);
|
46
|
+
|
47
|
+
if (
|
48
|
+
typeof replacement !== 'string' &&
|
49
|
+
typeof replacement !== 'number' &&
|
50
|
+
typeof replacement !== 'boolean'
|
51
|
+
) {
|
52
|
+
throw new Error(
|
53
|
+
'Failed to interpolate template: Missing or invalid value for ' +
|
54
|
+
`expression [${expression}] (expected string, number or boolean)`
|
55
|
+
);
|
56
|
+
}
|
57
|
+
|
58
|
+
return replacement;
|
59
|
+
}
|
60
|
+
);
|
61
|
+
}
|
@@ -9,15 +9,20 @@ export function isValidRoutePath(path: string): boolean;
|
|
9
9
|
* @param {Object} options - Scan options
|
10
10
|
* @param {string} options.dirPath - Directory path to scan
|
11
11
|
* @param {number} [options.maxDepth=1] - Maximum depth to scan
|
12
|
-
* @param {Set<string>} [options.skipFolders
|
13
|
-
*
|
12
|
+
* @param {Set<string>} [options.skipFolders] - Folders to skip
|
13
|
+
*
|
14
|
+
* @param {number} [depth=0] - Do not set manually!
|
15
|
+
*
|
16
|
+
* @returns {Promise<Array<{displayName: string, path: string, depth: number}>>}
|
17
|
+
*
|
14
18
|
* @throws {Error} If path is outside project routes directory
|
15
19
|
*/
|
16
20
|
export function scanRouteFolders({ dirPath, maxDepth, skipFolders }: {
|
17
21
|
dirPath: string;
|
18
22
|
maxDepth?: number;
|
19
23
|
skipFolders?: Set<string>;
|
20
|
-
}): Promise<Array<{
|
24
|
+
}, depth?: number): Promise<Array<{
|
21
25
|
displayName: string;
|
22
26
|
path: string;
|
27
|
+
depth: number;
|
23
28
|
}>>;
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import { readdir } from 'node:fs/promises';
|
2
2
|
import { join, resolve } from 'node:path';
|
3
3
|
|
4
|
+
import { kebabToTitleCase, basename } from '../../string/index.js';
|
5
|
+
|
4
6
|
/**
|
5
7
|
* Validates if a path is within the project's src/routes directory
|
6
8
|
* @param {string} path - Path to validate
|
@@ -17,20 +19,28 @@ export function isValidRoutePath(path) {
|
|
17
19
|
* @param {Object} options - Scan options
|
18
20
|
* @param {string} options.dirPath - Directory path to scan
|
19
21
|
* @param {number} [options.maxDepth=1] - Maximum depth to scan
|
20
|
-
* @param {Set<string>} [options.skipFolders
|
21
|
-
*
|
22
|
+
* @param {Set<string>} [options.skipFolders] - Folders to skip
|
23
|
+
*
|
24
|
+
* @param {number} [depth=0] - Do not set manually!
|
25
|
+
*
|
26
|
+
* @returns {Promise<Array<{displayName: string, path: string, depth: number}>>}
|
27
|
+
*
|
22
28
|
* @throws {Error} If path is outside project routes directory
|
23
29
|
*/
|
24
|
-
export async function scanRouteFolders(
|
25
|
-
dirPath,
|
26
|
-
|
27
|
-
|
28
|
-
|
30
|
+
export async function scanRouteFolders(
|
31
|
+
{ dirPath, maxDepth = 1, skipFolders },
|
32
|
+
depth = 0
|
33
|
+
) {
|
34
|
+
// console.debug({
|
35
|
+
// maxDepth,
|
36
|
+
// depth
|
37
|
+
// });
|
38
|
+
|
29
39
|
if (!isValidRoutePath(dirPath)) {
|
30
40
|
throw new Error('Invalid path: Must be within src/routes directory');
|
31
41
|
}
|
32
42
|
|
33
|
-
if (
|
43
|
+
if (depth > maxDepth) return [];
|
34
44
|
|
35
45
|
try {
|
36
46
|
const entries = await readdir(dirPath, { withFileTypes: true });
|
@@ -39,7 +49,7 @@ export async function scanRouteFolders({
|
|
39
49
|
for (const entry of entries) {
|
40
50
|
if (
|
41
51
|
!entry.isDirectory() ||
|
42
|
-
skipFolders
|
52
|
+
skipFolders?.has(entry.name) ||
|
43
53
|
entry.name.startsWith('.')
|
44
54
|
) {
|
45
55
|
continue;
|
@@ -54,21 +64,30 @@ export async function scanRouteFolders({
|
|
54
64
|
if (hasPageFile) {
|
55
65
|
results.push({
|
56
66
|
displayName: entry.name,
|
57
|
-
path: currentPath
|
67
|
+
path: currentPath,
|
68
|
+
depth
|
58
69
|
});
|
59
70
|
}
|
60
71
|
|
61
72
|
if (maxDepth > 1) {
|
62
|
-
const subFolders = await scanRouteFolders(
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
73
|
+
const subFolders = await scanRouteFolders(
|
74
|
+
{
|
75
|
+
dirPath: fullPath,
|
76
|
+
maxDepth,
|
77
|
+
skipFolders
|
78
|
+
},
|
79
|
+
depth + 1
|
80
|
+
);
|
67
81
|
|
68
82
|
for (const subFolder of subFolders) {
|
83
|
+
const path = `${currentPath}/${subFolder.path}`;
|
84
|
+
|
85
|
+
const displayName = kebabToTitleCase(basename(subFolder.path));
|
86
|
+
|
69
87
|
results.push({
|
70
|
-
displayName
|
71
|
-
path
|
88
|
+
displayName,
|
89
|
+
path,
|
90
|
+
depth: subFolder.depth
|
72
91
|
});
|
73
92
|
}
|
74
93
|
}
|