gr2m / javascript-plugin-architecture-with-typescript-definitions

Plugin architecture example with full TypeScript support

Repository from Github https://github.comgr2m/javascript-plugin-architecture-with-typescript-definitionsRepository from Github https://github.comgr2m/javascript-plugin-architecture-with-typescript-definitions

conditional plugin loading?

Uzlopak opened this issue · comments

Hi @gr2m ,

I wanted to tell you, that this plugin is great! Thank you very much!!!

Best Regards

Thanks @Uzlopak!

I'm not sure what you mean with "conditinal plugin loading"? Could you share a code example of what you are looking for?

Hi @gr2m ,

I started to write a Support request, then realized after 1-2 hours of try and error that your code already Covers all my needs. Thats why i thank you very much for your very useful piece of Code. If you would have Set your Emailadress in your Code i would have written you an Email.

The title ist so to say deprecated ;).

Should I send you the code what I wrote?

Btw. I saw you licensed it under ISC, but you wrote, that you extracted this code from octokit, which is licensed under MIT. Did you choose the different license on purpose?

I did not extract the code 1:1, more conceptually. All the code here is written from scratch. As far as I know, ISC is more permissive to MIT, but the two licenses are compatible, I don't really have a preference. ISC is the default license that npm sets for new projects so I went with that

And thank you for your kind words! Please share your code if it's Open Source, I'd love to see how you use it

@gr2m

I used it like this:

import { Base } from "javascript-plugin-architecture-with-typescript-definitions";

interface ResourcesAPIGroup_2_0 {
	foo(): string;
}

function ResourcesAPIGroup_2_0(instance: Base): ResourcesAPIGroup_2_0 {
	return {
		foo: () => "foo"
	};
}

function ResourcesAPIGroup_2_1(instance: Base): ResourcesAPIGroup_2_1 {
	return {
		foo: (value: string) => value
	};
}

export interface IRestAPIClientVersionConfiguration {
	resources: "2.0" | "2.1";
	metrics: "2.0" | "2.1";
}


interface ResourcesAPIGroup_2_1 {
	foo(value: string): string;
}

function MetricsAPIGroup_2_0(instance: Base): MetricsAPIGroup_2_0 {
	return {
		bar: () => "bar"
	};
}

function MetricsAPIGroup_2_1(instance: Base): MetricsAPIGroup_2_1 {
	return {
		bar: (value: string) => value
	};
}

interface MetricsAPIGroup_2_0 {
	bar(): string;
}

interface MetricsAPIGroup_2_1 {
	bar(value: string): string;
}

type ResourceAPIVersionInterface<T> =
	T extends { resources: "2.0" } ? ResourcesAPIGroup_2_0 :
	T extends { resources: "2.1" } ? ResourcesAPIGroup_2_1 :
	ResourcesAPIGroup_2_1;

type MetricsAPIVersionInterface<T> =
	T extends { metrics: "2.0" } ? MetricsAPIGroup_2_0 :
	T extends { metrics: "2.1" } ? MetricsAPIGroup_2_1 :
	MetricsAPIGroup_2_1;

function factory<T extends IRestAPIClientVersionConfiguration>(config: T): ResourceAPIVersionInterface<T> & MetricsAPIVersionInterface<T> {
	let FooBarTest;
	const plugins = [];

	switch (config.resources) {
		case "2.0":
			plugins.push(ResourcesAPIGroup_2_0);
			break;
		default:
		case "2.1":
			plugins.push(ResourcesAPIGroup_2_1);
			break;
	}
	switch (config.metrics) {
		case "2.0":
			plugins.push(MetricsAPIGroup_2_0);
			break;
		default:
		case "2.1":
			plugins.push(MetricsAPIGroup_2_1);
			break;
	}

	FooBarTest = Base.plugin(plugins);
	return new FooBarTest() as unknown as ResourceAPIVersionInterface<T> & MetricsAPIVersionInterface<T>;
}

const client2_1 = factory({ resources: "2.1", metrics: "2.1" });
client2_1.foo("her");
client2_1.bar("other");

const client2_0 = factory({ resources: "2.0", metrics: "2.0" });
client2_0.foo();
client2_0.bar();

Previous the factory was a RestApiClient class but I didnt know how to do the conditional plugin typing for classes, but I guess I will do it the old function equals object JS-style ;). Or do you know how I could do it with classes?

Thanks for sharing!

Or do you know how I could do it with classes?

Unfortunately no