@yeoman/namespace
Version:
Namespace parsing for yeoman's generator/environment stack
168 lines • 5.23 kB
JavaScript
// ===================== | == @ ======== scope ======== | ===== unscoped ===== | = : ========== generator ======== | = @ ===== semver ===== @ | = # ========= instanceId ======== | == + ======== method ======= |= flags = |
const NAMESPACE_REGEX = /^(?:(@[a-z\d-~][a-z\d-._~]*)\/)?([a-z\d-~][a-z\d-._~]*)(?::((?:[a-z\d-~][a-z\d-._~]*:?)*))?(?:@([a-z\d-.~><+=^* ]*)@?)?(?:#((?:[a-z\d-~][a-z\d-._~]*|\*)))?(?:\+((?:[a-zA-Z\d]\w*\+?)*))?(\?)?$/;
const groups = {
complete: 0,
scope: 1,
unscoped: 2,
generator: 3,
semver: 4,
instanceId: 5,
method: 6,
flags: 7,
};
const flags = { optional: '?' };
function parseNamespace(complete) {
if (typeof complete !== 'string') {
throw new TypeError('Must be a string');
}
const result = NAMESPACE_REGEX.exec(complete);
if (!result) {
return;
}
const parsed = { complete };
// Populate fields
for (const [name, value] of Object.entries(groups)) {
if (result[value]) {
parsed[name] = result[value];
}
}
return new YeomanNamespace(parsed);
}
export class YeomanNamespace {
_original;
scope;
unscoped;
generator;
instanceId;
semver;
methods;
flags;
command;
constructor(parsed) {
this._original = parsed.complete;
this.scope = parsed.scope;
this.unscoped = parsed.unscoped;
this.generator = parsed.generator;
this.instanceId = parsed.instanceId;
this.semver = parsed.semver;
this.methods = parsed.method?.split('+');
this.flags = parsed.flags;
// Populate flags
if (this.flags) {
for (const [name, value] of Object.entries(flags)) {
if (this.flags === value) {
this[name] = true;
}
else {
delete this[name];
}
}
}
}
get _scopeAddition() {
return this.scope ? `${this.scope}/` : '';
}
get generatorName() {
return this.generator ? `:${this.generator}` : '';
}
get instanceName() {
return this.instanceId ? `#${this.instanceId}` : '';
}
get complete() {
let methods = '';
if (this.methods && this.methods.length > 0) {
methods = `+${this.methods.join('+')}`;
}
const postSemver = `${this.instanceName}${methods}${this.flags ?? ''}`;
return `${this.namespace}${this._semverAddition(postSemver)}`;
}
get packageNamespace() {
return `${this._scopeAddition}${this.unscoped}`;
}
get namespace() {
return `${this.packageNamespace}${this.generatorName}`;
}
set namespace(namespace) {
const parsed = parseNamespace(namespace);
if (!parsed) {
throw new Error(`Error parsing namespace ${namespace}`);
}
this._update(parsed);
}
get unscopedNamespace() {
return `${this.unscoped}${this.generatorName}`;
}
get id() {
return `${this.namespace}${this.instanceName}`;
}
get generatorHint() {
return `${this._scopeAddition}generator-${this.unscoped}`;
}
get versionedHint() {
return this.semver ? `${this.generatorHint}@"${this.semver}"` : this.generatorHint;
}
with(newValues) {
return new YeomanNamespace({
...this,
...newValues,
});
}
toString() {
return this.complete;
}
_semverAddition(post) {
if (!this.semver) {
return post ?? '';
}
if (post) {
return `@${this.semver}@${post}`;
}
return `@${this.semver}`;
}
_update(parsed) {
this.scope = parsed.scope ?? this.scope;
this.unscoped = parsed.unscoped ?? this.unscoped;
this.generator = parsed.generator ?? this.generator;
this.instanceId = parsed.instanceId ?? this.instanceId;
this.command = parsed.command ?? this.command;
this.flags = parsed.flags ?? this.flags;
}
}
/**
* Convert a namespace to a namespace object
*/
export function toNamespace(namespace) {
return isNamespaceObject(namespace) ? namespace : parseNamespace(namespace);
}
/**
* Convert a package name to a namespace object
*
* @throws if not a valid generator package name (starts with 'generator-')
*/
export function namespaceFromPackageName(packageName) {
const namespace = parseNamespace(packageName);
if (!namespace?.unscoped?.startsWith('generator-')) {
throw new Error(`${packageName} is not a valid generator package name`);
}
namespace.unscoped = namespace.unscoped.replace(/^generator-/, '');
return namespace;
}
/**
* Convert a namespace to a namespace object
*
* @throws if not a valid namespace
*/
export function requireNamespace(namespace) {
const parsed = toNamespace(namespace);
if (!parsed) {
throw new Error(`Error parsing namespace ${namespace.toString()}`);
}
return parsed;
}
/**
* Test if the object is an YeomanNamespace instance.
*/
export function isNamespaceObject(namespace) {
return namespace?.constructor?.name === 'YeomanNamespace';
}
//# sourceMappingURL=index.js.map