@zokugun/fs-path 0.1.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/LICENSE +22 -0
- package/README.md +153 -0
- package/lib/cjs/absolute.cjs +6 -0
- package/lib/cjs/absolute.d.cts +3 -0
- package/lib/cjs/dir.cjs +6 -0
- package/lib/cjs/dir.d.cts +3 -0
- package/lib/cjs/index.cjs +50 -0
- package/lib/cjs/index.d.cts +47 -0
- package/lib/cjs/is-in-dir.cjs +18 -0
- package/lib/cjs/is-in-dir.d.cts +3 -0
- package/lib/cjs/is-in-dirs.cjs +38 -0
- package/lib/cjs/is-in-dirs.d.cts +3 -0
- package/lib/cjs/is-safe-path.cjs +42 -0
- package/lib/cjs/is-safe-path.d.cts +8 -0
- package/lib/cjs/is-safe-segment.cjs +27 -0
- package/lib/cjs/is-safe-segment.d.cts +4 -0
- package/lib/cjs/join.cjs +14 -0
- package/lib/cjs/join.d.cts +3 -0
- package/lib/cjs/parent.cjs +14 -0
- package/lib/cjs/parent.d.cts +3 -0
- package/lib/cjs/platform.cjs +67 -0
- package/lib/cjs/platform.d.cts +2 -0
- package/lib/cjs/resolve.cjs +42 -0
- package/lib/cjs/resolve.d.cts +3 -0
- package/lib/cjs/sanitize.cjs +62 -0
- package/lib/cjs/sanitize.d.cts +10 -0
- package/lib/cjs/types.cjs +2 -0
- package/lib/cjs/types.d.cts +34 -0
- package/lib/cjs/untildify.cjs +25 -0
- package/lib/cjs/untildify.d.cts +3 -0
- package/lib/cjs/utils/get-home.cjs +12 -0
- package/lib/cjs/utils/get-home.d.cts +1 -0
- package/lib/cjs/utils/get-user-home.cjs +18 -0
- package/lib/cjs/utils/get-user-home.d.cts +1 -0
- package/lib/esm/absolute.d.mts +3 -0
- package/lib/esm/absolute.mjs +3 -0
- package/lib/esm/dir.d.mts +3 -0
- package/lib/esm/dir.mjs +3 -0
- package/lib/esm/index.d.mts +47 -0
- package/lib/esm/index.mjs +29 -0
- package/lib/esm/is-in-dir.d.mts +3 -0
- package/lib/esm/is-in-dir.mjs +15 -0
- package/lib/esm/is-in-dirs.d.mts +3 -0
- package/lib/esm/is-in-dirs.mjs +35 -0
- package/lib/esm/is-safe-path.d.mts +8 -0
- package/lib/esm/is-safe-path.mjs +36 -0
- package/lib/esm/is-safe-segment.d.mts +4 -0
- package/lib/esm/is-safe-segment.mjs +21 -0
- package/lib/esm/join.d.mts +3 -0
- package/lib/esm/join.mjs +11 -0
- package/lib/esm/parent.d.mts +3 -0
- package/lib/esm/parent.mjs +11 -0
- package/lib/esm/platform.d.mts +2 -0
- package/lib/esm/platform.mjs +61 -0
- package/lib/esm/resolve.d.mts +3 -0
- package/lib/esm/resolve.mjs +36 -0
- package/lib/esm/sanitize.d.mts +10 -0
- package/lib/esm/sanitize.mjs +56 -0
- package/lib/esm/types.d.mts +34 -0
- package/lib/esm/types.mjs +1 -0
- package/lib/esm/untildify.d.mts +3 -0
- package/lib/esm/untildify.mjs +22 -0
- package/lib/esm/utils/get-home.d.mts +1 -0
- package/lib/esm/utils/get-home.mjs +6 -0
- package/lib/esm/utils/get-user-home.d.mts +1 -0
- package/lib/esm/utils/get-user-home.mjs +12 -0
- package/package.json +83 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sanitize = sanitize;
|
|
7
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
8
|
+
const fs_path_sanitize_1 = require("@zokugun/fs-path-sanitize");
|
|
9
|
+
const is_it_type_1 = require("@zokugun/is-it-type");
|
|
10
|
+
const xtry_1 = require("@zokugun/xtry");
|
|
11
|
+
function sanitize(_nodePath, localPath) {
|
|
12
|
+
let target;
|
|
13
|
+
if (localPath.separator === '\\') {
|
|
14
|
+
target = 'windows.safe';
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
const system = node_os_1.default.platform();
|
|
18
|
+
target = system === 'darwin' ? 'macos.safe' : 'linux.safe';
|
|
19
|
+
}
|
|
20
|
+
const sanitizer = fs_path_sanitize_1.Sanitizer.getInstance(target);
|
|
21
|
+
return (path, options = {}) => {
|
|
22
|
+
const resolvedPath = localPath.resolve(path);
|
|
23
|
+
let parents;
|
|
24
|
+
if ((0, is_it_type_1.isString)(options.parent)) {
|
|
25
|
+
parents = [options.parent];
|
|
26
|
+
}
|
|
27
|
+
if ((0, is_it_type_1.isString)(options.parents)) {
|
|
28
|
+
parents = [options.parents];
|
|
29
|
+
}
|
|
30
|
+
else if ((0, is_it_type_1.isArray)(options.parents)) {
|
|
31
|
+
parents = options.parents;
|
|
32
|
+
}
|
|
33
|
+
let sanitizedPath;
|
|
34
|
+
if (!options.target || options.target === 'auto') {
|
|
35
|
+
sanitizedPath = sanitizer.sanitizePath(resolvedPath, {
|
|
36
|
+
absolute: true,
|
|
37
|
+
replacement: options.replacement,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
sanitizedPath = (0, fs_path_sanitize_1.sanitizePath)(resolvedPath, {
|
|
42
|
+
absolute: true,
|
|
43
|
+
replacement: options.replacement,
|
|
44
|
+
target: options.target,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (sanitizedPath.fails) {
|
|
48
|
+
return sanitizedPath;
|
|
49
|
+
}
|
|
50
|
+
if (parents) {
|
|
51
|
+
if (localPath.isInDirs(sanitizedPath.value, parents)) {
|
|
52
|
+
return sanitizedPath;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
return (0, xtry_1.err)('Invalid path: not within allowed parents');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
return sanitizedPath;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type path from 'node:path';
|
|
2
|
+
import { type Target } from '@zokugun/fs-path-sanitize';
|
|
3
|
+
import { type DResult } from '@zokugun/xtry';
|
|
4
|
+
import { type PlatformPath } from './types.cjs';
|
|
5
|
+
export declare function sanitize(_nodePath: path.PlatformPath, localPath: PlatformPath): (path: string, options?: {
|
|
6
|
+
parent?: string | null;
|
|
7
|
+
parents?: string | string[] | null;
|
|
8
|
+
replacement?: string | null;
|
|
9
|
+
target?: Target | 'auto';
|
|
10
|
+
}) => DResult<string>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Target } from '@zokugun/fs-path-sanitize';
|
|
2
|
+
import { type DResult } from '@zokugun/xtry';
|
|
3
|
+
export type PlatformPath = {
|
|
4
|
+
readonly delimiter: ';' | ':';
|
|
5
|
+
readonly separator: '\\' | '/';
|
|
6
|
+
readonly posix: PlatformPath;
|
|
7
|
+
readonly win32: PlatformPath;
|
|
8
|
+
absolute: (...paths: string[]) => string;
|
|
9
|
+
dir: (path: string) => string;
|
|
10
|
+
extension: (path: string) => string;
|
|
11
|
+
isAbsolute: (path: string) => boolean;
|
|
12
|
+
isInDir: (file: string, dir: string) => boolean;
|
|
13
|
+
isInDirs: (file: string, directories: string[]) => boolean;
|
|
14
|
+
isSafePath: (path: string, options?: {
|
|
15
|
+
parent?: string | null;
|
|
16
|
+
parents?: string | string[] | null;
|
|
17
|
+
target?: Target | 'auto';
|
|
18
|
+
}) => boolean;
|
|
19
|
+
isSafeSegment: (segment: string, target?: Target | 'auto') => boolean;
|
|
20
|
+
join: (...paths: string[]) => string;
|
|
21
|
+
leaf: (path: string, suffix?: string) => string;
|
|
22
|
+
matchesGlob?: (path: string, pattern: string) => boolean;
|
|
23
|
+
normalize: (path: string) => string;
|
|
24
|
+
parent: (file: string) => string;
|
|
25
|
+
relative: (from: string, to: string) => string;
|
|
26
|
+
resolve: (...paths: string[]) => string;
|
|
27
|
+
sanitize: (path: string, options?: {
|
|
28
|
+
parent?: string | null;
|
|
29
|
+
parents?: string | string[] | null;
|
|
30
|
+
replacement?: string | null;
|
|
31
|
+
target?: Target | 'auto';
|
|
32
|
+
}) => DResult<string>;
|
|
33
|
+
untildify: (path: string) => string;
|
|
34
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.untildify = untildify;
|
|
4
|
+
const is_it_type_1 = require("@zokugun/is-it-type");
|
|
5
|
+
const get_home_js_1 = require("./utils/get-home.cjs");
|
|
6
|
+
const get_user_home_js_1 = require("./utils/get-user-home.cjs");
|
|
7
|
+
const TILDE_REGEX = /^~(?=$|\/|\\)/;
|
|
8
|
+
const USER_REGEX = /^~([^/\\]+)(.*)$/;
|
|
9
|
+
function untildify(_nodePath, _localPath) {
|
|
10
|
+
return (path) => {
|
|
11
|
+
const homedir = (0, get_home_js_1.getHome)();
|
|
12
|
+
if ((0, is_it_type_1.isString)(homedir) && TILDE_REGEX.test(path)) {
|
|
13
|
+
return homedir + path.slice(1);
|
|
14
|
+
}
|
|
15
|
+
const match = USER_REGEX.exec(path);
|
|
16
|
+
if (match) {
|
|
17
|
+
const [, username, rest] = match;
|
|
18
|
+
const userHome = (0, get_user_home_js_1.getUserHome)(username);
|
|
19
|
+
if ((0, is_it_type_1.isString)(userHome)) {
|
|
20
|
+
return userHome + rest;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return path;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getHome = getHome;
|
|
7
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
8
|
+
let $home;
|
|
9
|
+
function getHome() {
|
|
10
|
+
$home ??= node_os_1.default.homedir();
|
|
11
|
+
return $home;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getHome(): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getUserHome = getUserHome;
|
|
7
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
8
|
+
const get_home_js_1 = require("./get-home.cjs");
|
|
9
|
+
let $username;
|
|
10
|
+
function getUserHome(username) {
|
|
11
|
+
$username ??= node_os_1.default.userInfo().username;
|
|
12
|
+
if (username === $username) {
|
|
13
|
+
return (0, get_home_js_1.getHome)();
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getUserHome(username: string): string | null;
|
package/lib/esm/dir.mjs
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type PlatformPath } from './types.mjs';
|
|
2
|
+
declare const absolute: (...paths: string[]) => string, delimiter: ";" | ":", extension: (path: string) => string, isAbsolute: (path: string) => boolean, join: (...paths: string[]) => string, leaf: (path: string, suffix?: string) => string, matchesGlob: ((path: string, pattern: string) => boolean) | undefined, normalize: (path: string) => string, parent: (file: string) => string, isInDir: (file: string, dir: string) => boolean, isInDirs: (file: string, directories: string[]) => boolean, isSafePath: (path: string, options?: {
|
|
3
|
+
parent?: string | null;
|
|
4
|
+
parents?: string | string[] | null;
|
|
5
|
+
target?: Target | "auto";
|
|
6
|
+
}) => boolean, isSafeSegment: (segment: string, target?: Target | "auto") => boolean, posix: PlatformPath, relative: (from: string, to: string) => string, resolve: (...paths: string[]) => string, sanitize: (path: string, options?: {
|
|
7
|
+
parent?: string | null;
|
|
8
|
+
parents?: string | string[] | null;
|
|
9
|
+
replacement?: string | null;
|
|
10
|
+
target?: Target | "auto";
|
|
11
|
+
}) => DResult<string>, separator: "\\" | "/", untildify: (path: string) => string, win32: PlatformPath;
|
|
12
|
+
export { type PlatformPath, absolute, delimiter, extension, isAbsolute, join, leaf, matchesGlob, normalize, parent, isInDir, isInDirs, isSafePath, isSafeSegment, posix, relative, resolve, sanitize, separator, untildify, win32, };
|
|
13
|
+
import { type Target } from "@zokugun/fs-path-sanitize";
|
|
14
|
+
import { type DResult } from "@zokugun/xtry";
|
|
15
|
+
declare const _default: {
|
|
16
|
+
PlatformPath: PlatformPath;
|
|
17
|
+
absolute: (...paths: string[]) => string;
|
|
18
|
+
delimiter: ";" | ":";
|
|
19
|
+
extension: (path: string) => string;
|
|
20
|
+
isAbsolute: (path: string) => boolean;
|
|
21
|
+
join: (...paths: string[]) => string;
|
|
22
|
+
leaf: (path: string, suffix?: string) => string;
|
|
23
|
+
matchesGlob: ((path: string, pattern: string) => boolean) | undefined;
|
|
24
|
+
normalize: (path: string) => string;
|
|
25
|
+
parent: (file: string) => string;
|
|
26
|
+
isInDir: (file: string, dir: string) => boolean;
|
|
27
|
+
isInDirs: (file: string, directories: string[]) => boolean;
|
|
28
|
+
isSafePath: (path: string, options?: {
|
|
29
|
+
parent?: string | null;
|
|
30
|
+
parents?: string | string[] | null;
|
|
31
|
+
target?: Target | "auto";
|
|
32
|
+
}) => boolean;
|
|
33
|
+
isSafeSegment: (segment: string, target?: Target | "auto") => boolean;
|
|
34
|
+
posix: PlatformPath;
|
|
35
|
+
relative: (from: string, to: string) => string;
|
|
36
|
+
resolve: (...paths: string[]) => string;
|
|
37
|
+
sanitize: (path: string, options?: {
|
|
38
|
+
parent?: string | null;
|
|
39
|
+
parents?: string | string[] | null;
|
|
40
|
+
replacement?: string | null;
|
|
41
|
+
target?: Target | "auto";
|
|
42
|
+
}) => DResult<string>;
|
|
43
|
+
separator: "\\" | "/";
|
|
44
|
+
untildify: (path: string) => string;
|
|
45
|
+
win32: PlatformPath;
|
|
46
|
+
};
|
|
47
|
+
export default _default;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DEFAULT_PLATFORM } from './platform.mjs';
|
|
2
|
+
const { absolute, delimiter, extension, isAbsolute, join, leaf, matchesGlob, normalize, parent, isInDir, isInDirs, isSafePath, isSafeSegment, posix, relative, resolve, sanitize, separator, untildify, win32, } = DEFAULT_PLATFORM;
|
|
3
|
+
/* eslint-disable unicorn/prefer-export-from */
|
|
4
|
+
export { absolute, delimiter, extension, isAbsolute, join, leaf, matchesGlob, normalize, parent, isInDir, isInDirs, isSafePath, isSafeSegment, posix, relative, resolve, sanitize, separator, untildify, win32, };
|
|
5
|
+
/* eslint-enable unicorn/prefer-export-from */
|
|
6
|
+
// eslint-disable-next-line import/no-anonymous-default-export
|
|
7
|
+
export default {
|
|
8
|
+
PlatformPath: undefined,
|
|
9
|
+
absolute,
|
|
10
|
+
delimiter,
|
|
11
|
+
extension,
|
|
12
|
+
isAbsolute,
|
|
13
|
+
join,
|
|
14
|
+
leaf,
|
|
15
|
+
matchesGlob,
|
|
16
|
+
normalize,
|
|
17
|
+
parent,
|
|
18
|
+
isInDir,
|
|
19
|
+
isInDirs,
|
|
20
|
+
isSafePath,
|
|
21
|
+
isSafeSegment,
|
|
22
|
+
posix,
|
|
23
|
+
relative,
|
|
24
|
+
resolve,
|
|
25
|
+
sanitize,
|
|
26
|
+
separator,
|
|
27
|
+
untildify,
|
|
28
|
+
win32,
|
|
29
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function isInDir(_nodePath, localPath) {
|
|
2
|
+
return (path, parent) => {
|
|
3
|
+
let resolvedPath = localPath.resolve(path);
|
|
4
|
+
let resolvedParent = localPath.resolve(parent);
|
|
5
|
+
if (localPath.separator === '\\') {
|
|
6
|
+
resolvedPath = resolvedPath.toLowerCase();
|
|
7
|
+
resolvedParent = resolvedParent.toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
if (resolvedPath === resolvedParent) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
const suffixedParent = resolvedParent.endsWith(localPath.separator) ? resolvedParent : resolvedParent + localPath.separator;
|
|
13
|
+
return resolvedPath.startsWith(suffixedParent);
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
2
|
+
export function isInDirs(_nodePath, localPath) {
|
|
3
|
+
if (localPath.separator === '\\') {
|
|
4
|
+
return (path, parents) => {
|
|
5
|
+
const resolvedPath = localPath.resolve(path).toLowerCase();
|
|
6
|
+
for (const parent of parents) {
|
|
7
|
+
const resolvedParent = localPath.resolve(parent).toLowerCase();
|
|
8
|
+
if (resolvedPath === resolvedParent) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
const suffixedParent = resolvedParent.endsWith(localPath.separator) ? resolvedParent : resolvedParent + localPath.separator;
|
|
12
|
+
if (resolvedPath.startsWith(suffixedParent)) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
return (path, parents) => {
|
|
21
|
+
const resolvedPath = localPath.resolve(path);
|
|
22
|
+
for (const parent of parents) {
|
|
23
|
+
const resolvedParent = localPath.resolve(parent);
|
|
24
|
+
if (resolvedPath === resolvedParent) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
const suffixedParent = resolvedParent.endsWith(localPath.separator) ? resolvedParent : resolvedParent + localPath.separator;
|
|
28
|
+
if (resolvedPath.startsWith(suffixedParent)) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type path from 'node:path';
|
|
2
|
+
import { type Target } from '@zokugun/fs-path-sanitize';
|
|
3
|
+
import { type PlatformPath } from './types.mjs';
|
|
4
|
+
export declare function isSafePath(_nodePath: path.PlatformPath, localPath: PlatformPath): (path: string, options?: {
|
|
5
|
+
parent?: string | null;
|
|
6
|
+
parents?: string | string[] | null;
|
|
7
|
+
target?: Target | 'auto';
|
|
8
|
+
}) => boolean;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import { isSafePath as isSafe, Sanitizer } from '@zokugun/fs-path-sanitize';
|
|
3
|
+
import { isArray, isString } from '@zokugun/is-it-type';
|
|
4
|
+
export function isSafePath(_nodePath, localPath) {
|
|
5
|
+
let target;
|
|
6
|
+
if (localPath.separator === '\\') {
|
|
7
|
+
target = 'windows.safe';
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
const system = os.platform();
|
|
11
|
+
target = system === 'darwin' ? 'macos.safe' : 'linux.safe';
|
|
12
|
+
}
|
|
13
|
+
const sanitizer = Sanitizer.getInstance(target);
|
|
14
|
+
return (path, options = {}) => {
|
|
15
|
+
let parents;
|
|
16
|
+
if (isString(options.parent)) {
|
|
17
|
+
parents = [options.parent];
|
|
18
|
+
}
|
|
19
|
+
if (isString(options.parents)) {
|
|
20
|
+
parents = [options.parents];
|
|
21
|
+
}
|
|
22
|
+
else if (isArray(options.parents)) {
|
|
23
|
+
parents = options.parents;
|
|
24
|
+
}
|
|
25
|
+
const safe = !options.target || options.target === 'auto' ? sanitizer.isSafePath(path) : isSafe(path, target);
|
|
26
|
+
if (!safe) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
else if (parents) {
|
|
30
|
+
return localPath.isInDirs(path, parents);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type path from 'node:path';
|
|
2
|
+
import { type Target } from '@zokugun/fs-path-sanitize';
|
|
3
|
+
import { type PlatformPath } from './types.mjs';
|
|
4
|
+
export declare function isSafeSegment(_nodePath: path.PlatformPath, localPath: PlatformPath): (segment: string, target?: Target | 'auto') => boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import { isSafeSegment as isSafe, Sanitizer } from '@zokugun/fs-path-sanitize';
|
|
3
|
+
export function isSafeSegment(_nodePath, localPath) {
|
|
4
|
+
let target;
|
|
5
|
+
if (localPath.separator === '\\') {
|
|
6
|
+
target = 'windows.safe';
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
const system = os.platform();
|
|
10
|
+
target = system === 'darwin' ? 'macos.safe' : 'linux.safe';
|
|
11
|
+
}
|
|
12
|
+
const sanitizer = Sanitizer.getInstance(target);
|
|
13
|
+
return (segment, target) => {
|
|
14
|
+
if (!target || target === 'auto') {
|
|
15
|
+
return sanitizer.isSafePath(segment);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
return isSafe(segment, target);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
package/lib/esm/join.mjs
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { absolute } from './absolute.mjs';
|
|
3
|
+
import { dir } from './dir.mjs';
|
|
4
|
+
import { isInDir } from './is-in-dir.mjs';
|
|
5
|
+
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
6
|
+
import { isInDirs } from './is-in-dirs.mjs';
|
|
7
|
+
import { isSafePath } from './is-safe-path.mjs';
|
|
8
|
+
import { isSafeSegment } from './is-safe-segment.mjs';
|
|
9
|
+
import { join } from './join.mjs';
|
|
10
|
+
import { parent } from './parent.mjs';
|
|
11
|
+
import { resolve } from './resolve.mjs';
|
|
12
|
+
import { sanitize } from './sanitize.mjs';
|
|
13
|
+
import { untildify } from './untildify.mjs';
|
|
14
|
+
function buildPlatform(path) {
|
|
15
|
+
const { basename: leaf, delimiter, extname: extension, isAbsolute, normalize, relative, sep: separator, } = path;
|
|
16
|
+
const result = {
|
|
17
|
+
delimiter,
|
|
18
|
+
separator,
|
|
19
|
+
extension,
|
|
20
|
+
isAbsolute,
|
|
21
|
+
leaf,
|
|
22
|
+
matchesGlob: path.matchesGlob ?? undefined,
|
|
23
|
+
normalize,
|
|
24
|
+
relative,
|
|
25
|
+
};
|
|
26
|
+
result.absolute = absolute(path, result);
|
|
27
|
+
result.dir = dir(path, result);
|
|
28
|
+
result.isInDir = isInDir(path, result);
|
|
29
|
+
result.isInDirs = isInDirs(path, result);
|
|
30
|
+
result.isSafePath = isSafePath(path, result);
|
|
31
|
+
result.isSafeSegment = isSafeSegment(path, result);
|
|
32
|
+
result.join = join(path, result);
|
|
33
|
+
result.parent = parent(path, result);
|
|
34
|
+
result.resolve = resolve(path, result);
|
|
35
|
+
result.sanitize = sanitize(path, result);
|
|
36
|
+
result.untildify = untildify(path, result);
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
const POSIX_PLATFORM = buildPlatform(path.posix);
|
|
40
|
+
const WIN32_PLATFORM = buildPlatform(path.win32);
|
|
41
|
+
Object.defineProperties(POSIX_PLATFORM, {
|
|
42
|
+
posix: {
|
|
43
|
+
value: POSIX_PLATFORM,
|
|
44
|
+
writable: false,
|
|
45
|
+
},
|
|
46
|
+
win32: {
|
|
47
|
+
value: WIN32_PLATFORM,
|
|
48
|
+
writable: false,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
Object.defineProperties(WIN32_PLATFORM, {
|
|
52
|
+
posix: {
|
|
53
|
+
value: POSIX_PLATFORM,
|
|
54
|
+
writable: false,
|
|
55
|
+
},
|
|
56
|
+
win32: {
|
|
57
|
+
value: WIN32_PLATFORM,
|
|
58
|
+
writable: false,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
export const DEFAULT_PLATFORM = (path === path.posix ? POSIX_PLATFORM : WIN32_PLATFORM);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import { isString } from '@zokugun/is-it-type';
|
|
3
|
+
import { getHome } from './utils/get-home.mjs';
|
|
4
|
+
import { getUserHome } from './utils/get-user-home.mjs';
|
|
5
|
+
const TILDE_REGEX = /^~(?=$|\/|\\)/;
|
|
6
|
+
const USER_REGEX = /^~([^/\\]+)(.*)$/;
|
|
7
|
+
export function resolve(nodePath, _localPath) {
|
|
8
|
+
return (...paths) => {
|
|
9
|
+
if (paths.length === 0) {
|
|
10
|
+
return process.cwd();
|
|
11
|
+
}
|
|
12
|
+
else if (nodePath.isAbsolute(paths[0])) {
|
|
13
|
+
return nodePath.normalize(nodePath.join(...paths));
|
|
14
|
+
}
|
|
15
|
+
else if (TILDE_REGEX.test(paths[0])) {
|
|
16
|
+
const homedir = getHome();
|
|
17
|
+
if (isString(homedir)) {
|
|
18
|
+
paths.shift();
|
|
19
|
+
return nodePath.normalize(nodePath.join(homedir, ...paths));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const match = USER_REGEX.exec(paths[0]);
|
|
24
|
+
if (match) {
|
|
25
|
+
const [, username, rest] = match;
|
|
26
|
+
const userHome = getUserHome(username);
|
|
27
|
+
if (isString(userHome)) {
|
|
28
|
+
paths.shift();
|
|
29
|
+
return nodePath.normalize(nodePath.join(userHome + rest, ...paths));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
paths.unshift();
|
|
34
|
+
return nodePath.normalize(nodePath.join(process.cwd(), ...paths));
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type path from 'node:path';
|
|
2
|
+
import { type Target } from '@zokugun/fs-path-sanitize';
|
|
3
|
+
import { type DResult } from '@zokugun/xtry';
|
|
4
|
+
import { type PlatformPath } from './types.mjs';
|
|
5
|
+
export declare function sanitize(_nodePath: path.PlatformPath, localPath: PlatformPath): (path: string, options?: {
|
|
6
|
+
parent?: string | null;
|
|
7
|
+
parents?: string | string[] | null;
|
|
8
|
+
replacement?: string | null;
|
|
9
|
+
target?: Target | 'auto';
|
|
10
|
+
}) => DResult<string>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import { sanitizePath, Sanitizer } from '@zokugun/fs-path-sanitize';
|
|
3
|
+
import { isArray, isString } from '@zokugun/is-it-type';
|
|
4
|
+
import { err } from '@zokugun/xtry';
|
|
5
|
+
export function sanitize(_nodePath, localPath) {
|
|
6
|
+
let target;
|
|
7
|
+
if (localPath.separator === '\\') {
|
|
8
|
+
target = 'windows.safe';
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
const system = os.platform();
|
|
12
|
+
target = system === 'darwin' ? 'macos.safe' : 'linux.safe';
|
|
13
|
+
}
|
|
14
|
+
const sanitizer = Sanitizer.getInstance(target);
|
|
15
|
+
return (path, options = {}) => {
|
|
16
|
+
const resolvedPath = localPath.resolve(path);
|
|
17
|
+
let parents;
|
|
18
|
+
if (isString(options.parent)) {
|
|
19
|
+
parents = [options.parent];
|
|
20
|
+
}
|
|
21
|
+
if (isString(options.parents)) {
|
|
22
|
+
parents = [options.parents];
|
|
23
|
+
}
|
|
24
|
+
else if (isArray(options.parents)) {
|
|
25
|
+
parents = options.parents;
|
|
26
|
+
}
|
|
27
|
+
let sanitizedPath;
|
|
28
|
+
if (!options.target || options.target === 'auto') {
|
|
29
|
+
sanitizedPath = sanitizer.sanitizePath(resolvedPath, {
|
|
30
|
+
absolute: true,
|
|
31
|
+
replacement: options.replacement,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
sanitizedPath = sanitizePath(resolvedPath, {
|
|
36
|
+
absolute: true,
|
|
37
|
+
replacement: options.replacement,
|
|
38
|
+
target: options.target,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (sanitizedPath.fails) {
|
|
42
|
+
return sanitizedPath;
|
|
43
|
+
}
|
|
44
|
+
if (parents) {
|
|
45
|
+
if (localPath.isInDirs(sanitizedPath.value, parents)) {
|
|
46
|
+
return sanitizedPath;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
return err('Invalid path: not within allowed parents');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
return sanitizedPath;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|