@cjser/filenamify 7.0.2-cjser.2 → 7.0.3-cjser.2
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-cjser/browser.cjs +13 -8
- package/dist-cjser/index.cjs +15 -10
- package/filenamify.d.ts +4 -0
- package/filenamify.js +16 -11
- package/package.json +5 -5
- package/readme.md +4 -0
package/dist-cjser/browser.cjs
CHANGED
|
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
));
|
|
27
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
28
|
|
|
29
|
-
// packages/@cjser/filenamify.tmp-
|
|
29
|
+
// packages/@cjser/filenamify.tmp-25-1788284040504/filenamify.js
|
|
30
30
|
var filenamify_exports = {};
|
|
31
31
|
__export(filenamify_exports, {
|
|
32
32
|
default: () => filenamify
|
|
@@ -36,6 +36,8 @@ var import_filename_reserved_regex = __toESM(require("@cjser/filename-reserved-r
|
|
|
36
36
|
var MAX_FILENAME_LENGTH = 100;
|
|
37
37
|
var reRelativePath = /^\.+(\\|\/)|^\.+$/;
|
|
38
38
|
var reTrailingDotsAndSpaces = /[. ]+$/;
|
|
39
|
+
var reTrailingSpaces = / +$/;
|
|
40
|
+
var reWindowsReservedName = (0, import_filename_reserved_regex.windowsReservedNameRegex)();
|
|
39
41
|
var reControlChars = /[\p{Control}\p{Format}\p{Zl}\p{Zp}\uFFF0-\uFFFF]/gu;
|
|
40
42
|
var reControlCharsTest = /[\p{Control}\p{Format}\p{Zl}\p{Zp}\uFFF0-\uFFFF]/u;
|
|
41
43
|
var isZeroWidthJoiner = (char) => char === "\u200D";
|
|
@@ -59,15 +61,18 @@ function truncateFilename(filename, maxLength) {
|
|
|
59
61
|
const extension = filename.slice(extensionIndex);
|
|
60
62
|
const baseBudget = Math.max(0, maxLength - extension.length);
|
|
61
63
|
const truncatedBase = truncateByGraphemeBudget(base, baseBudget);
|
|
62
|
-
return truncatedBase.replace(
|
|
64
|
+
return truncatedBase.replace(reTrailingSpaces, "") + extension;
|
|
63
65
|
}
|
|
64
66
|
function ensureNonWindowsReservedName(filename, replacement) {
|
|
65
|
-
|
|
66
|
-
const base = extensionIndex === -1 ? filename : filename.slice(0, extensionIndex);
|
|
67
|
-
if (!(0, import_filename_reserved_regex.windowsReservedNameRegex)().test(base)) {
|
|
67
|
+
if (!reWindowsReservedName.test(filename)) {
|
|
68
68
|
return filename;
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
const extensionIndex = filename.indexOf(".");
|
|
71
|
+
const base = extensionIndex === -1 ? filename : filename.slice(0, extensionIndex);
|
|
72
|
+
const baseWithoutTrailingSpaces = base.replace(reTrailingSpaces, "");
|
|
73
|
+
const extension = extensionIndex === -1 ? "" : filename.slice(extensionIndex);
|
|
74
|
+
const candidate = (baseWithoutTrailingSpaces + replacement + extension).replace(reTrailingDotsAndSpaces, "");
|
|
75
|
+
return reWindowsReservedName.test(candidate) ? baseWithoutTrailingSpaces + "!" + extension : candidate;
|
|
71
76
|
}
|
|
72
77
|
function filenamify(string, options = {}) {
|
|
73
78
|
if (typeof string !== "string") {
|
|
@@ -85,8 +90,8 @@ function filenamify(string, options = {}) {
|
|
|
85
90
|
string = string.replaceAll(reRepeatedReservedCharacters, "$1");
|
|
86
91
|
}
|
|
87
92
|
string = string.replace(reTrailingDotsAndSpaces, "");
|
|
88
|
-
string = string.replace(reRelativePath, replacement);
|
|
89
|
-
string = string.replace((0, import_filename_reserved_regex.default)(), replacement);
|
|
93
|
+
string = string.replace(reRelativePath, () => replacement);
|
|
94
|
+
string = string.replace((0, import_filename_reserved_regex.default)(), () => replacement);
|
|
90
95
|
string = string.replaceAll(reControlChars, (char) => isZeroWidthJoiner(char) ? char : replacement);
|
|
91
96
|
string = string.replace(reTrailingDotsAndSpaces, "");
|
|
92
97
|
if (string.length === 0) {
|
package/dist-cjser/index.cjs
CHANGED
|
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
));
|
|
27
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
28
|
|
|
29
|
-
// packages/@cjser/filenamify.tmp-
|
|
29
|
+
// packages/@cjser/filenamify.tmp-25-1788284040504/index.js
|
|
30
30
|
var index_exports = {};
|
|
31
31
|
__export(index_exports, {
|
|
32
32
|
default: () => filenamify,
|
|
@@ -34,11 +34,13 @@ __export(index_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
|
-
// packages/@cjser/filenamify.tmp-
|
|
37
|
+
// packages/@cjser/filenamify.tmp-25-1788284040504/filenamify.js
|
|
38
38
|
var import_filename_reserved_regex = __toESM(require("@cjser/filename-reserved-regex"), 1);
|
|
39
39
|
var MAX_FILENAME_LENGTH = 100;
|
|
40
40
|
var reRelativePath = /^\.+(\\|\/)|^\.+$/;
|
|
41
41
|
var reTrailingDotsAndSpaces = /[. ]+$/;
|
|
42
|
+
var reTrailingSpaces = / +$/;
|
|
43
|
+
var reWindowsReservedName = (0, import_filename_reserved_regex.windowsReservedNameRegex)();
|
|
42
44
|
var reControlChars = /[\p{Control}\p{Format}\p{Zl}\p{Zp}\uFFF0-\uFFFF]/gu;
|
|
43
45
|
var reControlCharsTest = /[\p{Control}\p{Format}\p{Zl}\p{Zp}\uFFF0-\uFFFF]/u;
|
|
44
46
|
var isZeroWidthJoiner = (char) => char === "\u200D";
|
|
@@ -62,15 +64,18 @@ function truncateFilename(filename, maxLength) {
|
|
|
62
64
|
const extension = filename.slice(extensionIndex);
|
|
63
65
|
const baseBudget = Math.max(0, maxLength - extension.length);
|
|
64
66
|
const truncatedBase = truncateByGraphemeBudget(base, baseBudget);
|
|
65
|
-
return truncatedBase.replace(
|
|
67
|
+
return truncatedBase.replace(reTrailingSpaces, "") + extension;
|
|
66
68
|
}
|
|
67
69
|
function ensureNonWindowsReservedName(filename, replacement) {
|
|
68
|
-
|
|
69
|
-
const base = extensionIndex === -1 ? filename : filename.slice(0, extensionIndex);
|
|
70
|
-
if (!(0, import_filename_reserved_regex.windowsReservedNameRegex)().test(base)) {
|
|
70
|
+
if (!reWindowsReservedName.test(filename)) {
|
|
71
71
|
return filename;
|
|
72
72
|
}
|
|
73
|
-
|
|
73
|
+
const extensionIndex = filename.indexOf(".");
|
|
74
|
+
const base = extensionIndex === -1 ? filename : filename.slice(0, extensionIndex);
|
|
75
|
+
const baseWithoutTrailingSpaces = base.replace(reTrailingSpaces, "");
|
|
76
|
+
const extension = extensionIndex === -1 ? "" : filename.slice(extensionIndex);
|
|
77
|
+
const candidate = (baseWithoutTrailingSpaces + replacement + extension).replace(reTrailingDotsAndSpaces, "");
|
|
78
|
+
return reWindowsReservedName.test(candidate) ? baseWithoutTrailingSpaces + "!" + extension : candidate;
|
|
74
79
|
}
|
|
75
80
|
function filenamify(string, options = {}) {
|
|
76
81
|
if (typeof string !== "string") {
|
|
@@ -88,8 +93,8 @@ function filenamify(string, options = {}) {
|
|
|
88
93
|
string = string.replaceAll(reRepeatedReservedCharacters, "$1");
|
|
89
94
|
}
|
|
90
95
|
string = string.replace(reTrailingDotsAndSpaces, "");
|
|
91
|
-
string = string.replace(reRelativePath, replacement);
|
|
92
|
-
string = string.replace((0, import_filename_reserved_regex.default)(), replacement);
|
|
96
|
+
string = string.replace(reRelativePath, () => replacement);
|
|
97
|
+
string = string.replace((0, import_filename_reserved_regex.default)(), () => replacement);
|
|
93
98
|
string = string.replaceAll(reControlChars, (char) => isZeroWidthJoiner(char) ? char : replacement);
|
|
94
99
|
string = string.replace(reTrailingDotsAndSpaces, "");
|
|
95
100
|
if (string.length === 0) {
|
|
@@ -121,7 +126,7 @@ function truncateByGraphemeBudget(input, budget) {
|
|
|
121
126
|
return output;
|
|
122
127
|
}
|
|
123
128
|
|
|
124
|
-
// packages/@cjser/filenamify.tmp-
|
|
129
|
+
// packages/@cjser/filenamify.tmp-25-1788284040504/filenamify-path.js
|
|
125
130
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
126
131
|
function filenamifyPath(filePath, options) {
|
|
127
132
|
filePath = import_node_path.default.resolve(filePath);
|
package/filenamify.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export type Options = {
|
|
|
4
4
|
|
|
5
5
|
Cannot contain: `<` `>` `:` `"` `/` `\` `|` `?` `*` or control characters.
|
|
6
6
|
|
|
7
|
+
If the replacement would leave the result as a Windows reserved name, `!` is used instead.
|
|
8
|
+
|
|
7
9
|
@default '!'
|
|
8
10
|
*/
|
|
9
11
|
readonly replacement?: string;
|
|
@@ -13,6 +15,8 @@ export type Options = {
|
|
|
13
15
|
|
|
14
16
|
Only the base of the filename is truncated, preserving the extension. If the extension itself is longer than `maxLength`, you will get a string that is longer than `maxLength`, so you need to check for that if you allow arbitrary extensions.
|
|
15
17
|
|
|
18
|
+
The result may also exceed `maxLength` when a suffix is needed to avoid a Windows reserved name.
|
|
19
|
+
|
|
16
20
|
Truncation is grapheme-aware and will not split Unicode characters (surrogate pairs or extended grapheme clusters). If the remaining budget (after accounting for the extension) is smaller than a whole grapheme, the base filename may be truncated to an empty string to avoid splitting.
|
|
17
21
|
|
|
18
22
|
Systems generally allow up to 255 characters, but we default to 100 for usability reasons.
|
package/filenamify.js
CHANGED
|
@@ -5,6 +5,8 @@ const MAX_FILENAME_LENGTH = 100;
|
|
|
5
5
|
|
|
6
6
|
const reRelativePath = /^\.+(\\|\/)|^\.+$/;
|
|
7
7
|
const reTrailingDotsAndSpaces = /[. ]+$/;
|
|
8
|
+
const reTrailingSpaces = / +$/;
|
|
9
|
+
const reWindowsReservedName = windowsReservedNameRegex();
|
|
8
10
|
|
|
9
11
|
// Remove all problematic characters except zero-width joiner (\u200D) needed for emoji
|
|
10
12
|
const reControlChars = /[\p{Control}\p{Format}\p{Zl}\p{Zp}\uFFF0-\uFFFF]/gu;
|
|
@@ -44,20 +46,23 @@ function truncateFilename(filename, maxLength) {
|
|
|
44
46
|
const truncatedBase = truncateByGraphemeBudget(base, baseBudget);
|
|
45
47
|
|
|
46
48
|
// Strip trailing spaces from base (not periods - they're not trailing in final filename)
|
|
47
|
-
return truncatedBase.replace(
|
|
49
|
+
return truncatedBase.replace(reTrailingSpaces, '') + extension;
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
function ensureNonWindowsReservedName(filename, replacement) {
|
|
51
|
-
|
|
52
|
-
const base = extensionIndex === -1 ? filename : filename.slice(0, extensionIndex);
|
|
53
|
-
|
|
54
|
-
if (!windowsReservedNameRegex().test(base)) {
|
|
53
|
+
if (!reWindowsReservedName.test(filename)) {
|
|
55
54
|
return filename;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
const extensionIndex = filename.indexOf('.');
|
|
58
|
+
const base = extensionIndex === -1 ? filename : filename.slice(0, extensionIndex);
|
|
59
|
+
const baseWithoutTrailingSpaces = base.replace(reTrailingSpaces, '');
|
|
60
|
+
const extension = extensionIndex === -1 ? '' : filename.slice(extensionIndex);
|
|
61
|
+
const candidate = (baseWithoutTrailingSpaces + replacement + extension).replace(reTrailingDotsAndSpaces, '');
|
|
62
|
+
|
|
63
|
+
return reWindowsReservedName.test(candidate)
|
|
64
|
+
? baseWithoutTrailingSpaces + '!' + extension
|
|
65
|
+
: candidate;
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
export default function filenamify(string, options = {}) {
|
|
@@ -88,8 +93,8 @@ export default function filenamify(string, options = {}) {
|
|
|
88
93
|
// so they get stripped rather than replaced
|
|
89
94
|
string = string.replace(reTrailingDotsAndSpaces, '');
|
|
90
95
|
|
|
91
|
-
string = string.replace(reRelativePath, replacement);
|
|
92
|
-
string = string.replace(filenameReservedRegex(), replacement);
|
|
96
|
+
string = string.replace(reRelativePath, () => replacement);
|
|
97
|
+
string = string.replace(filenameReservedRegex(), () => replacement);
|
|
93
98
|
string = string.replaceAll(reControlChars, char => isZeroWidthJoiner(char) ? char : replacement);
|
|
94
99
|
|
|
95
100
|
// Trim trailing spaces and periods again (in case replacement created new ones)
|
|
@@ -112,7 +117,7 @@ export default function filenamify(string, options = {}) {
|
|
|
112
117
|
string = string.replace(reTrailingDotsAndSpaces, '');
|
|
113
118
|
|
|
114
119
|
// Check for Windows reserved names after truncation and stripping
|
|
115
|
-
// Windows compatibility takes precedence over maxLength, so
|
|
120
|
+
// Windows compatibility takes precedence over maxLength, so the result may exceed it
|
|
116
121
|
string = ensureNonWindowsReservedName(string, replacement);
|
|
117
122
|
|
|
118
123
|
return string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cjser/filenamify",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.3-cjser.2",
|
|
4
4
|
"description": "Convert a string to a valid safe filename",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"dirname"
|
|
57
57
|
],
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@cjser/filename-reserved-regex": "4.0.
|
|
59
|
+
"@cjser/filename-reserved-regex": "4.0.1-cjser.2"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"ava": "^6.4.1",
|
|
@@ -65,11 +65,11 @@
|
|
|
65
65
|
"types": "./index.d.ts",
|
|
66
66
|
"main": "./dist-cjser/index.cjs",
|
|
67
67
|
"cjser": {
|
|
68
|
-
"sourceVersion": "7.0.
|
|
68
|
+
"sourceVersion": "7.0.3",
|
|
69
69
|
"cjserVersion": 2,
|
|
70
70
|
"original": {
|
|
71
71
|
"name": "filenamify",
|
|
72
|
-
"version": "7.0.
|
|
72
|
+
"version": "7.0.3",
|
|
73
73
|
"exports": {
|
|
74
74
|
".": {
|
|
75
75
|
"types": "./index.d.ts",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
},
|
|
83
83
|
"repository": "sindresorhus/filenamify",
|
|
84
84
|
"dependencies": {
|
|
85
|
-
"filename-reserved-regex": "^4.0.
|
|
85
|
+
"filename-reserved-regex": "^4.0.1"
|
|
86
86
|
},
|
|
87
87
|
"files": [
|
|
88
88
|
"filenamify-path.d.ts",
|
package/readme.md
CHANGED
|
@@ -54,6 +54,8 @@ String to use as replacement for reserved filename characters.
|
|
|
54
54
|
|
|
55
55
|
Cannot contain: `<` `>` `:` `"` `/` `\` `|` `?` `*` or control characters.
|
|
56
56
|
|
|
57
|
+
If the replacement would leave the result as a Windows reserved name, `!` is used instead.
|
|
58
|
+
|
|
57
59
|
##### maxLength
|
|
58
60
|
|
|
59
61
|
Type: `number`\
|
|
@@ -63,6 +65,8 @@ Truncate the filename to the given length.
|
|
|
63
65
|
|
|
64
66
|
Only the base of the filename is truncated, preserving the extension. If the extension itself is longer than `maxLength`, you will get a string that is longer than `maxLength`, so you need to check for that if you allow arbitrary extensions.
|
|
65
67
|
|
|
68
|
+
The result may also exceed `maxLength` when a suffix is needed to avoid a Windows reserved name.
|
|
69
|
+
|
|
66
70
|
Truncation is grapheme-aware and will not split Unicode characters (surrogate pairs or extended grapheme clusters). If the remaining budget (after accounting for the extension) is smaller than a whole grapheme, the base filename may be truncated to an empty string to avoid splitting.
|
|
67
71
|
|
|
68
72
|
Systems generally allow up to 255 characters, but we default to 100 for usability reasons.
|