feat(alias): filename -> snake_case alias converter
This commit is contained in:
30
src/alias.js
Normal file
30
src/alias.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// src/alias.js
|
||||||
|
// Pure functions for deriving snake_case aliases from sprite filenames.
|
||||||
|
// No I/O.
|
||||||
|
|
||||||
|
const path = require('node:path');
|
||||||
|
const SUPPORTED_EXT = ['.png', '.webp', '.jpg', '.jpeg'];
|
||||||
|
|
||||||
|
function stripPrefix(name, prefix) {
|
||||||
|
if (!prefix) return name;
|
||||||
|
if (name.startsWith(prefix)) return name.slice(prefix.length);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CamelCase -> snake_case. Boundary: lowercase/digit -> uppercase.
|
||||||
|
function camelToSnakeCase(s) {
|
||||||
|
return s
|
||||||
|
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
||||||
|
.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function aliasFromFilename(filename, opts = {}) {
|
||||||
|
const ext = path.extname(filename).toLowerCase();
|
||||||
|
let base = SUPPORTED_EXT.includes(ext)
|
||||||
|
? filename.slice(0, -ext.length)
|
||||||
|
: filename;
|
||||||
|
if (opts.stripPrefix) base = stripPrefix(base, opts.stripPrefix);
|
||||||
|
return camelToSnakeCase(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { stripPrefix, camelToSnakeCase, aliasFromFilename };
|
||||||
50
tests/alias.test.js
Normal file
50
tests/alias.test.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
const { test } = require('node:test');
|
||||||
|
const assert = require('node:assert');
|
||||||
|
const { stripPrefix, camelToSnakeCase, aliasFromFilename } = require('../src/alias');
|
||||||
|
|
||||||
|
test('stripPrefix: strips matching prefix', () => {
|
||||||
|
assert.strictEqual(stripPrefix('TC_Basics Asset Pack_Bed1', 'TC_Basics Asset Pack_'), 'Bed1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('stripPrefix: returns unchanged when no match', () => {
|
||||||
|
assert.strictEqual(stripPrefix('Bed1', 'TC_Basics Asset Pack_'), 'Bed1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('stripPrefix: empty prefix returns unchanged', () => {
|
||||||
|
assert.strictEqual(stripPrefix('Bed1', ''), 'Bed1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('camelToSnakeCase: BenchTable1 -> bench_table1', () => {
|
||||||
|
assert.strictEqual(camelToSnakeCase('BenchTable1'), 'bench_table1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('camelToSnakeCase: ArmourStand -> armour_stand', () => {
|
||||||
|
assert.strictEqual(camelToSnakeCase('ArmourStand'), 'armour_stand');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('camelToSnakeCase: Bed1 -> bed1', () => {
|
||||||
|
assert.strictEqual(camelToSnakeCase('Bed1'), 'bed1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('camelToSnakeCase: BarrelLarge -> barrel_large', () => {
|
||||||
|
assert.strictEqual(camelToSnakeCase('BarrelLarge'), 'barrel_large');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('camelToSnakeCase: already snake_case unchanged', () => {
|
||||||
|
assert.strictEqual(camelToSnakeCase('bench_table1'), 'bench_table1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('aliasFromFilename: full pipeline', () => {
|
||||||
|
const alias = aliasFromFilename('TC_Basics Asset Pack_BenchTable1.png', {
|
||||||
|
stripPrefix: 'TC_Basics Asset Pack_',
|
||||||
|
});
|
||||||
|
assert.strictEqual(alias, 'bench_table1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('aliasFromFilename: no opts -> bare-name snake_case', () => {
|
||||||
|
assert.strictEqual(aliasFromFilename('Bed1.png', {}), 'bed1');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('aliasFromFilename: handles .webp extension', () => {
|
||||||
|
assert.strictEqual(aliasFromFilename('Bed1.webp', {}), 'bed1');
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user