78 lines
2.3 KiB
TypeScript
78 lines
2.3 KiB
TypeScript
import { parse } from 'node:path';
|
|
import slash from 'slash';
|
|
import { escapeRegExp, findLast } from 'lodash-es';
|
|
|
|
type AsNamespaceOptions = {
|
|
lookups?: string[];
|
|
};
|
|
|
|
export const defaultLookups = ['.', 'generators', 'lib/generators', 'dist/generators'];
|
|
|
|
/**
|
|
* Given a String `filepath`, tries to figure out the relative namespace.
|
|
*
|
|
* ### Examples:
|
|
*
|
|
* this.namespace('backbone/all/index.js');
|
|
* // => backbone:all
|
|
*
|
|
* this.namespace('generator-backbone/model');
|
|
* // => backbone:model
|
|
*
|
|
* this.namespace('backbone.js');
|
|
* // => backbone
|
|
*
|
|
* this.namespace('generator-mocha/backbone/model/index.js');
|
|
* // => mocha:backbone:model
|
|
*
|
|
* @param filepath
|
|
* @param lookups paths
|
|
*/
|
|
export const asNamespace = (filepath: string, { lookups = defaultLookups }: AsNamespaceOptions): string => {
|
|
if (!filepath) {
|
|
throw new Error('Missing file path');
|
|
}
|
|
|
|
// Normalize path
|
|
let ns = slash(filepath);
|
|
|
|
// Ignore path before latest node_modules
|
|
const nodeModulesPath = '/node_modules/';
|
|
if (ns.includes(nodeModulesPath)) {
|
|
ns = ns.slice(ns.lastIndexOf(nodeModulesPath) + nodeModulesPath.length);
|
|
}
|
|
|
|
// Cleanup extension and normalize path for differents OS
|
|
const parsed = parse(ns);
|
|
ns = parsed.dir ? `${parsed.dir}/${parsed.name}` : parsed.name;
|
|
|
|
// Sort lookups by length so biggest are removed first
|
|
const nsLookups = [...lookups, '..']
|
|
.map(found => slash(found))
|
|
.sort((a, b) => a.split('/').length - b.split('/').length)
|
|
.toReversed();
|
|
|
|
// If `ns` contains a lookup dir in its path, remove it.
|
|
for (const lookup of nsLookups) {
|
|
// Only match full directory (begin with leading slash or start of input, end with trailing slash)
|
|
ns = ns.replaceAll(new RegExp(`(?:/|^)${escapeRegExp(lookup)}(?=/)`, 'g'), '');
|
|
}
|
|
|
|
const folders = ns.split('/');
|
|
const scope = findLast(folders, folder => folder.startsWith('@'));
|
|
|
|
// Cleanup `ns` from unwanted parts and then normalize slashes to `:`
|
|
ns = ns
|
|
.replaceAll('//', '') // Remove double `/`
|
|
.replace(/(.*generator-)/, '') // Remove before `generator-`
|
|
.replace(/\/(index|main)$/, '') // Remove `/index` or `/main`
|
|
.replace(/^\//, '') // Remove leading `/`
|
|
.replaceAll(/\/+/g, ':'); // Replace slashes by `:`
|
|
|
|
if (scope) {
|
|
ns = `${scope}/${ns}`;
|
|
}
|
|
|
|
return ns;
|
|
};
|