T3MP3ST public launch build
This commit is contained in:
1 parent
972247b881
commit
184c7d4e59
1589 files changed
+57150
-506
No files matched your search
@@ -0,0 +1,267 @@
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { extname, join } from 'node:path';
|
||||
import { createRequire } from 'node:module';
|
||||
import { toNamespace } from '@yeoman/namespace';
|
||||
import type {
|
||||
BaseEnvironment,
|
||||
BaseGenerator,
|
||||
BaseGeneratorConstructorMeta,
|
||||
BaseGeneratorMeta,
|
||||
GeneratorMeta,
|
||||
GetGeneratorConstructor,
|
||||
} from '@yeoman/types';
|
||||
import createDebug from 'debug';
|
||||
|
||||
const debug = createDebug('yeoman:environment:store');
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
/**
|
||||
* The Generator store
|
||||
* This is used to store generator (npm packages) reference and instantiate them when
|
||||
* requested.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
export default class Store {
|
||||
private readonly _meta: Record<string, GeneratorMeta> = {};
|
||||
// Store packages paths by ns
|
||||
private readonly _packagesPaths: Record<string, string[]> = {};
|
||||
// Store packages ns
|
||||
private readonly _packagesNS: string[] = [];
|
||||
|
||||
private readonly environment: BaseEnvironment;
|
||||
|
||||
constructor(environment: BaseEnvironment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a module under the namespace key
|
||||
* @param meta
|
||||
* @param generator - A generator module or a module path
|
||||
*/
|
||||
add<M extends BaseGeneratorMeta>(meta: M, Generator?: unknown): GeneratorMeta & M {
|
||||
if (typeof meta.resolved === 'string') {
|
||||
if (extname(meta.resolved)) {
|
||||
meta.resolved = join(meta.resolved);
|
||||
} else {
|
||||
try {
|
||||
// Resolve if meta.resolved is a package path.
|
||||
meta.resolved = require.resolve(meta.resolved);
|
||||
} catch {
|
||||
// Import must be a file, append index.js to directories
|
||||
meta.resolved = join(meta.resolved, 'index.js');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (meta.packagePath) {
|
||||
meta.packagePath = join(meta.packagePath);
|
||||
}
|
||||
|
||||
let importModule: (() => Promise<unknown>) | undefined;
|
||||
if (!Generator) {
|
||||
if (!meta.resolved) {
|
||||
throw new Error(`Generator Stub or resolved path is required for ${meta.namespace}`);
|
||||
}
|
||||
|
||||
importModule = () => {
|
||||
try {
|
||||
return require(meta.resolved!);
|
||||
} catch (error: any) {
|
||||
if (error.code === 'ERR_REQUIRE_ESM' || error.code === 'ERR_REQUIRE_ASYNC_MODULE') {
|
||||
return import(pathToFileURL(meta.resolved!).href);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let importPromise: Promise<unknown> | undefined;
|
||||
// eslint-disable-next-line prefer-const
|
||||
let generatorMeta: (GeneratorMeta & M) | undefined;
|
||||
|
||||
const importGenerator: GeneratorMeta['importGenerator'] = <G extends BaseGenerator>():
|
||||
| Promise<GetGeneratorConstructor<G> & BaseGeneratorConstructorMeta>
|
||||
| (GetGeneratorConstructor<G> & BaseGeneratorConstructorMeta) => {
|
||||
const handleImport = () => {
|
||||
if (importModule && !Generator) {
|
||||
const maybeModule = importModule();
|
||||
if ((maybeModule as any).then) {
|
||||
importPromise = maybeModule;
|
||||
return maybeModule
|
||||
.then((mod: any) => {
|
||||
Generator = mod;
|
||||
})
|
||||
.finally(() => {
|
||||
importPromise = undefined;
|
||||
});
|
||||
} else {
|
||||
Generator = maybeModule;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleModule = <G extends BaseGenerator>():
|
||||
| Promise<GetGeneratorConstructor<G> & BaseGeneratorConstructorMeta>
|
||||
| (GetGeneratorConstructor<G> & BaseGeneratorConstructorMeta) => {
|
||||
const factory = this.getFactory(Generator);
|
||||
if (typeof factory === 'function') {
|
||||
importPromise = factory(this.environment);
|
||||
return Promise.resolve(importPromise).then((mod: any) => {
|
||||
const generator = this._getGenerator<G>(mod, meta, generatorMeta);
|
||||
Generator = generator;
|
||||
importPromise = undefined;
|
||||
return generator;
|
||||
});
|
||||
}
|
||||
|
||||
return this._getGenerator<G>(Generator, meta, generatorMeta);
|
||||
};
|
||||
|
||||
if (importPromise) {
|
||||
return importPromise.then(() => Promise.resolve(handleImport()).then(() => handleModule()));
|
||||
}
|
||||
|
||||
const maybeImportPromise = handleImport();
|
||||
if (maybeImportPromise?.then) {
|
||||
return maybeImportPromise.then(() => handleModule());
|
||||
}
|
||||
return handleModule();
|
||||
};
|
||||
|
||||
const instantiate: GeneratorMeta['instantiate'] = async <G extends BaseGenerator>(arguments_: string[] = [], options: any = {}) =>
|
||||
this.environment.instantiate<G>(await importGenerator<G>(), { generatorArgs: arguments_, generatorOptions: options });
|
||||
const instantiateHelp: GeneratorMeta['instantiateHelp'] = async () => instantiate([], { help: true });
|
||||
const { packageNamespace } = toNamespace(meta.namespace) ?? {};
|
||||
|
||||
generatorMeta = {
|
||||
...meta,
|
||||
importGenerator,
|
||||
importModule,
|
||||
instantiate,
|
||||
instantiateHelp,
|
||||
packageNamespace,
|
||||
};
|
||||
this._meta[meta.namespace] = generatorMeta;
|
||||
|
||||
if (packageNamespace) {
|
||||
this.addPackageNamespace(packageNamespace);
|
||||
if (meta.packagePath) {
|
||||
this.addPackage(packageNamespace, meta.packagePath);
|
||||
}
|
||||
}
|
||||
|
||||
return generatorMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the module registered under the given namespace
|
||||
* @param {String} namespace
|
||||
* @return {Module}
|
||||
*/
|
||||
async get(namespace: string): Promise<GetGeneratorConstructor | undefined> {
|
||||
return this.getMeta(namespace)?.importGenerator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the module registered under the given namespace
|
||||
* @param {String} namespace
|
||||
* @return {Module}
|
||||
*/
|
||||
getMeta(namespace: string): GeneratorMeta | undefined {
|
||||
return this._meta[namespace];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of registered namespace.
|
||||
* @return {Array} Namespaces array
|
||||
*/
|
||||
namespaces() {
|
||||
return Object.keys(this._meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored generators meta data
|
||||
* @return {Object} Generators metadata
|
||||
*/
|
||||
getGeneratorsMeta() {
|
||||
return this._meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a package under the namespace key
|
||||
* @param {String} packageNS - The key under which the generator can be retrieved
|
||||
* @param {String} packagePath - The package path
|
||||
*/
|
||||
addPackage(packageNS: string, packagePath: string) {
|
||||
if (this._packagesPaths[packageNS]) {
|
||||
// Yo environment allows overriding, so the last added has preference.
|
||||
if (this._packagesPaths[packageNS][0] !== packagePath) {
|
||||
const packagePaths = this._packagesPaths[packageNS];
|
||||
debug(
|
||||
'Overriding a package with namespace %s and path %s, with path %s',
|
||||
packageNS,
|
||||
this._packagesPaths[packageNS][0],
|
||||
packagePath,
|
||||
);
|
||||
// Remove old packagePath
|
||||
const index = packagePaths.indexOf(packagePath);
|
||||
if (index !== -1) {
|
||||
packagePaths.splice(index, 1);
|
||||
}
|
||||
|
||||
packagePaths.splice(0, 0, packagePath);
|
||||
}
|
||||
} else {
|
||||
this._packagesPaths[packageNS] = [packagePath];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored packages namespaces with paths.
|
||||
* @return {Object} Stored packages namespaces with paths.
|
||||
*/
|
||||
getPackagesPaths() {
|
||||
return this._packagesPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a package ns
|
||||
* @param {String} packageNS - The key under which the generator can be retrieved
|
||||
*/
|
||||
addPackageNamespace(packageNS: string) {
|
||||
if (!this._packagesNS.includes(packageNS)) {
|
||||
this._packagesNS.push(packageNS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored packages namespaces.
|
||||
* @return {Array} Stored packages namespaces.
|
||||
*/
|
||||
|
||||
getPackagesNS(): string[] {
|
||||
return this._packagesNS;
|
||||
}
|
||||
|
||||
private getFactory(module: any) {
|
||||
// CJS is imported in default, for backward compatibility we support a Generator exported as `module.exports = { default }`
|
||||
return module.createGenerator ?? module.default?.createGenerator ?? module.default?.default?.createGenerator;
|
||||
}
|
||||
|
||||
private _getGenerator<G extends BaseGenerator>(
|
||||
module: any,
|
||||
meta: BaseGeneratorMeta,
|
||||
generatorMeta: BaseGeneratorMeta | undefined,
|
||||
): GetGeneratorConstructor<G> & BaseGeneratorConstructorMeta {
|
||||
const Generator = module.default?.default ?? module.default ?? module;
|
||||
if (typeof Generator !== 'function') {
|
||||
throw new TypeError("The generator doesn't provide a constructor.");
|
||||
}
|
||||
|
||||
Object.assign(Generator, meta);
|
||||
Generator._meta = generatorMeta;
|
||||
return Generator;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user