一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
96 行
2.4 KiB
TypeScript
96 行
2.4 KiB
TypeScript
// Based on @joplin/fork-uslug
|
|
//
|
|
// The original is Copyright (c) 2012 Jeremy Selier
|
|
//
|
|
// MIT Licensed
|
|
//
|
|
// You may find a copy of this license in the LICENSE file that should have been provided
|
|
// to you with a copy of this software.
|
|
|
|
const nodeEmoji = require('node-emoji');
|
|
|
|
// Very old browsers (e.g. Chrome < 64, which is from 2018) may not support
|
|
// \p{} regexes.
|
|
let regexes_: Record<string, RegExp> | undefined;
|
|
try {
|
|
regexes_ = {
|
|
// eslint-disable-next-line prefer-regex-literals -- Needed to prevent syntax errors
|
|
L: new RegExp('\\p{L}', 'u'), N: new RegExp('\\p{N}', 'u'), Z: new RegExp('\\p{Z}', 'u'), M: new RegExp('\\p{M}', 'u'),
|
|
};
|
|
} catch (error) {
|
|
console.error(error);
|
|
regexes_ = undefined;
|
|
}
|
|
|
|
const _unicodeCategory = function(c: string) {
|
|
if (!regexes_) {
|
|
console.warn('Unicode RegExps not loaded. Skipping category check.');
|
|
return undefined;
|
|
}
|
|
|
|
for (const [key, val] of Object.entries(regexes_)) {
|
|
if (c.match(val)) return key;
|
|
}
|
|
return undefined;
|
|
};
|
|
|
|
interface Options {
|
|
lower?: boolean;
|
|
spaces?: boolean;
|
|
allowedChars?: string;
|
|
}
|
|
|
|
export default function(string: string, options: Options = {}) {
|
|
string = string || '';
|
|
|
|
options = options || {};
|
|
|
|
const allowedChars = options.allowedChars || '-_~';
|
|
const lower = typeof options.lower === 'boolean' ? options.lower : true;
|
|
const spaces = typeof options.spaces === 'boolean' ? options.spaces : false;
|
|
|
|
const rv = [];
|
|
|
|
const noEmojiString: string = nodeEmoji.unemojify(string);
|
|
const chars = noEmojiString.normalize('NFKC').split('');
|
|
|
|
for (let i = 0; i < chars.length; i++) {
|
|
const c = chars[i];
|
|
const code = c.charCodeAt(0);
|
|
|
|
// Allow Common CJK Unified Ideographs
|
|
// See: http://www.unicode.org/versions/Unicode6.0.0/ch12.pdf - Table 12-2
|
|
|
|
if (0x4E00 <= code && code <= 0x9FFF) {
|
|
rv.push(c);
|
|
continue;
|
|
}
|
|
|
|
// Allow Hangul
|
|
if (0xAC00 <= code && code <= 0xD7A3) {
|
|
rv.push(c);
|
|
continue;
|
|
}
|
|
|
|
// Japanese ideographic punctuation
|
|
if ((0x3000 <= code && code <= 0x3002) || (0xFF01 <= code && code <= 0xFF02)) {
|
|
rv.push(' ');
|
|
}
|
|
|
|
if (allowedChars.indexOf(c) !== -1) {
|
|
rv.push(c);
|
|
continue;
|
|
}
|
|
|
|
const val = _unicodeCategory(c);
|
|
if (val && ~'LNM'.indexOf(val)) rv.push(c);
|
|
if (val && ~'Z'.indexOf(val)) rv.push(' ');
|
|
}
|
|
let slug = rv.join('').replace(/^\s+|\s+$/g, '').replace(/\s+/g, ' ');
|
|
|
|
if (!spaces) slug = slug.replace(/[\s-]+/g, '-');
|
|
if (lower) slug = slug.toLowerCase();
|
|
|
|
return slug;
|
|
}
|