Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a browser-only export #17

Merged
merged 6 commits into from Sep 24, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions filenamify-path.d.ts
@@ -0,0 +1,8 @@
import filenamify = require('./filenamify');

/**
Convert the filename in a path a valid filename and return the augmented path.
*/
declare const filenamifyPath: (path: string, options?: filenamify.Options) => string;

export = filenamifyPath;
10 changes: 10 additions & 0 deletions filenamify-path.js
@@ -0,0 +1,10 @@
'use strict';
const path = require('path');
const filenamify = require('./filenamify');

const filenamifyPath = (filePath, options) => {
filePath = path.resolve(filePath);
return path.join(path.dirname(filePath), filenamify(path.basename(filePath), options));
};

module.exports = filenamifyPath;
39 changes: 39 additions & 0 deletions filenamify.d.ts
@@ -0,0 +1,39 @@
declare namespace filenamify {
interface Options {
/**
String to use as replacement for reserved filename characters.

Cannot contain: `<` `>` `:` `"` `/` `\` `|` `?` `*`

@default '!'
*/
readonly replacement?: string;

/**
Truncate the filename to the given length.

Systems generally allow up to 255 characters, but we default to 100 for usability reasons.

@default 100
*/
readonly maxLength?: number;
}
}

/**
Convert a string to a valid filename.

@example
```
import filenamify = require('filenamify');

filenamify('<foo/bar>');
//=> 'foo!bar'

filenamify('foo:"bar"', {replacement: '🐴'});
//=> 'foo🐴bar'
```
*/
declare const filenamify: (string: string, options?: filenamify.Options) => string;

export = filenamify;
38 changes: 38 additions & 0 deletions filenamify.js
@@ -0,0 +1,38 @@
'use strict';
const trimRepeated = require('trim-repeated');
const filenameReservedRegex = require('filename-reserved-regex');
const stripOuter = require('strip-outer');

// Doesn't make sense to have longer filenames
const MAX_FILENAME_LENGTH = 100;

const reControlChars = /[\u0000-\u001f\u0080-\u009f]/g; // eslint-disable-line no-control-regex
const reRelativePath = /^\.+/;

const filenamify = (string, options = {}) => {
if (typeof string !== 'string') {
throw new TypeError('Expected a string');
}

const replacement = options.replacement === undefined ? '!' : options.replacement;

if (filenameReservedRegex().test(replacement) && reControlChars.test(replacement)) {
throw new Error('Replacement string cannot contain reserved filename characters');
}

string = string.replace(filenameReservedRegex(), replacement);
string = string.replace(reControlChars, replacement);
string = string.replace(reRelativePath, replacement);

if (replacement.length > 0) {
string = trimRepeated(string, replacement);
string = string.length > 1 ? stripOuter(string, replacement) : string;
}

string = filenameReservedRegex.windowsNames().test(string) ? string + replacement : string;
string = string.slice(0, typeof options.maxLength === 'number' ? options.maxLength : MAX_FILENAME_LENGTH);

return string;
};

module.exports = filenamify;
32 changes: 5 additions & 27 deletions index.d.ts
@@ -1,26 +1,7 @@
declare namespace filenamify {
interface Options {
/**
String to use as replacement for reserved filename characters.
import filenamify = require('./filenamify');
import filenamifyPath = require('./filenamify-path');

Cannot contain: `<` `>` `:` `"` `/` `\` `|` `?` `*`

@default '!'
*/
readonly replacement?: string;

/**
Truncate the filename to the given length.

Systems generally allow up to 255 characters, but we default to 100 for usability reasons.

@default 100
*/
readonly maxLength?: number;
}
}

declare const filenamify: {
declare const filenamifyCombined: {
/**
Convert a string to a valid filename.

Expand All @@ -37,10 +18,7 @@ declare const filenamify: {
*/
(string: string, options?: filenamify.Options): string;

/**
Convert the filename in a path a valid filename and return the augmented path.
*/
path(path: string, options?: filenamify.Options): string;
path: typeof filenamifyPath;
};

export = filenamify;
export = filenamifyCombined;
44 changes: 4 additions & 40 deletions index.js
@@ -1,44 +1,8 @@
'use strict';
const path = require('path');
const trimRepeated = require('trim-repeated');
const filenameReservedRegex = require('filename-reserved-regex');
const stripOuter = require('strip-outer');
const filenamify = require('./filenamify');
const filenamifyPath = require('./filenamify-path');

// Doesn't make sense to have longer filenames
const MAX_FILENAME_LENGTH = 100;

const reControlChars = /[\u0000-\u001f\u0080-\u009f]/g; // eslint-disable-line no-control-regex
const reRelativePath = /^\.+/;

const filenamify = (string, options = {}) => {
if (typeof string !== 'string') {
throw new TypeError('Expected a string');
}

const replacement = options.replacement === undefined ? '!' : options.replacement;

if (filenameReservedRegex().test(replacement) && reControlChars.test(replacement)) {
throw new Error('Replacement string cannot contain reserved filename characters');
}

string = string.replace(filenameReservedRegex(), replacement);
string = string.replace(reControlChars, replacement);
string = string.replace(reRelativePath, replacement);

if (replacement.length > 0) {
string = trimRepeated(string, replacement);
string = string.length > 1 ? stripOuter(string, replacement) : string;
}

string = filenameReservedRegex.windowsNames().test(string) ? string + replacement : string;
string = string.slice(0, typeof options.maxLength === 'number' ? options.maxLength : MAX_FILENAME_LENGTH);

return string;
};

filenamify.path = (filePath, options) => {
filePath = path.resolve(filePath);
return path.join(path.dirname(filePath), filenamify(path.basename(filePath), options));
};
const filenamifyCombined = filenamify;
filenamifyCombined.path = filenamifyPath;

module.exports = filenamify;
5 changes: 5 additions & 0 deletions package.json
Expand Up @@ -19,6 +19,11 @@
"index.js",
"index.d.ts"
],
"exports": {
".": "./index.js",
"./filenamify": "./filenamify.js",
"./filenamify-path": "./filenamify-path.js"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not what we discussed in the issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure what you mean here, but if you meant that you don't want to provide the filenamify-path export then I've just pushed a commit that removes it.

I've also changed the name of the filenamify export to browser, as suggested by you in the issue. Again, it's always easy to change it.

And if there's anything else you want changed, please feel free to tell me and I'll change it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's what I meant. Sorry if that was not clear.

},
"keywords": [
"filename",
"safe",
Expand Down