尾缀识别
This commit is contained in:
1 parent
d9f7bd2f89
commit
94e9304d9e
34 files changed
+971
-13
No files matched your search
@@ -55,4 +55,35 @@ async function resolveDataPath(app) {
|
||||
return path.join(process.env.XDG_CONFIG_HOME || path.join(home, '.config'), 'Eagle');
|
||||
}
|
||||
|
||||
module.exports = { createStore, resolveDataPath };
|
||||
// 尾缀表是全局偏好(不是每个素材一份):同一台机器上所有素材、所有库共用。
|
||||
// 查看器在加载资源前读取它,用户的增删都会立即落盘。
|
||||
function createSuffixStore(userDataPath) {
|
||||
const directory = path.join(userDataPath, 'SpineViewer');
|
||||
const file = path.join(directory, 'suffix-settings.json');
|
||||
return {
|
||||
file,
|
||||
read() {
|
||||
try {
|
||||
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
|
||||
return Array.isArray(data.suffixes) ? data.suffixes : [];
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') return [];
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
// 仅在用户通过下拉列表增删尾缀时调用。
|
||||
write(suffixes) {
|
||||
if (!Array.isArray(suffixes)) throw new TypeError('尾缀设置必须为数组');
|
||||
fs.mkdirSync(directory, { recursive: true });
|
||||
const temp = file + '.' + crypto.randomBytes(8).toString('hex') + '.tmp';
|
||||
try {
|
||||
fs.writeFileSync(temp, JSON.stringify({ suffixes }, null, 2) + '\n', { flag: 'wx' });
|
||||
fs.renameSync(temp, file);
|
||||
} finally {
|
||||
try { fs.unlinkSync(temp); } catch (e) { if (e.code !== 'ENOENT') throw e; }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { createStore, createSuffixStore, resolveDataPath };
|
||||
@@ -19,8 +19,56 @@ const fileIndexCache = new Map();
|
||||
const skeletonJsonCache = new Map();
|
||||
const JSON_PROBE_BYTES = 256 * 1024;
|
||||
|
||||
// Spine 导出常见的后缀,匹配时归一化掉(支持 - 与 _ 两种分隔符)
|
||||
const SUFFIX_RE = /[-_](pro|ess|pma|base|atlas|data)$/i;
|
||||
// Spine 导出常见的尾缀,匹配时归一化掉(支持 - 与 _ 两种分隔符)
|
||||
// 例:hero-mesh.skel / hero-data.json / hero-pma.atlas 都归一为 hero
|
||||
const DEFAULT_SUFFIXES = ['pro', 'ess', 'pma', 'base', 'atlas', 'data', 'mesh'];
|
||||
// 用户可在查看器里添加自己的尾缀;为避免正则注入,只允许字母、数字、- 与 _,
|
||||
// 且必须以字母或数字开头。SUFFIX_MAX_LENGTH 必须与下面的正则保持一致(有测试守着)。
|
||||
const SUFFIX_MAX_LENGTH = 50;
|
||||
const SUFFIX_NAME_RE = /^[a-z0-9](?:[a-z0-9_-]{0,49})$/i;
|
||||
let activeSuffixes = DEFAULT_SUFFIXES.slice();
|
||||
let suffixRe = buildSuffixRe(activeSuffixes);
|
||||
|
||||
function escapeRegExp(text) {
|
||||
return String(text).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function buildSuffixRe(list) {
|
||||
if (!list || list.length === 0) return null;
|
||||
return new RegExp('[-_](' + list.map(escapeRegExp).join('|') + ')$', 'i');
|
||||
}
|
||||
|
||||
/** 校验并归一化单个尾缀名(去掉前导分隔符并转小写);非法返回 null */
|
||||
function normalizeSuffixName(raw) {
|
||||
const name = String(raw == null ? '' : raw).trim().replace(/^[-_]+/, '');
|
||||
return SUFFIX_NAME_RE.test(name) ? name.toLowerCase() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户自定义尾缀(内置尾缀始终生效),返回当前生效的完整列表。
|
||||
* 非法或重复的名字会被安静地忽略,不信任磁盘上的内容。
|
||||
*/
|
||||
function setSuffixes(list) {
|
||||
const custom = [];
|
||||
for (const raw of Array.isArray(list) ? list : []) {
|
||||
const name = normalizeSuffixName(raw);
|
||||
if (!name || DEFAULT_SUFFIXES.indexOf(name) !== -1) continue;
|
||||
if (custom.indexOf(name) === -1) custom.push(name);
|
||||
}
|
||||
activeSuffixes = DEFAULT_SUFFIXES.concat(custom);
|
||||
suffixRe = buildSuffixRe(activeSuffixes);
|
||||
return getSuffixes();
|
||||
}
|
||||
|
||||
/** 当前生效的尾缀(内置 + 自定义) */
|
||||
function getSuffixes() {
|
||||
return activeSuffixes.slice();
|
||||
}
|
||||
|
||||
/** 仅用户自定义(非内置)的尾缀,用于持久化 */
|
||||
function getCustomSuffixes() {
|
||||
return activeSuffixes.filter((name) => DEFAULT_SUFFIXES.indexOf(name) === -1);
|
||||
}
|
||||
|
||||
function unsafeAtlasPath(name, reason) {
|
||||
const error = new Error('Atlas 贴图路径不安全:' + JSON.stringify(String(name)) + '(' + reason + ')');
|
||||
@@ -132,9 +180,10 @@ function stemOf(name) {
|
||||
return name.slice(0, name.length - ext.length);
|
||||
}
|
||||
|
||||
/** 归一化 stem,去掉 Spine 常见后缀,用于跨文件匹配 */
|
||||
/** 归一化 stem,去掉内置与用户自定义的尾缀,用于跨文件匹配 */
|
||||
function normalizeStem(name) {
|
||||
return stemOf(name).toLowerCase().replace(SUFFIX_RE, '');
|
||||
const lower = stemOf(name).toLowerCase();
|
||||
return suffixRe ? lower.replace(suffixRe, '') : lower;
|
||||
}
|
||||
|
||||
/** 从 JSON 文本中读取 spine 版本 */
|
||||
@@ -760,6 +809,12 @@ module.exports = {
|
||||
isTextureFile,
|
||||
stemOf,
|
||||
normalizeStem,
|
||||
DEFAULT_SUFFIXES,
|
||||
SUFFIX_MAX_LENGTH,
|
||||
normalizeSuffixName,
|
||||
setSuffixes,
|
||||
getSuffixes,
|
||||
getCustomSuffixes,
|
||||
detectVersion,
|
||||
detectVersionFromJson,
|
||||
detectVersionFromBuffer,
|
||||
|
||||
Reference in new issue
Block a user