@shopware-ag/storefront-types 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,3 +23,29 @@ To have the types active, you need to create a `tsconfig.json` (`src/Resources/a
23
23
  }
24
24
  }
25
25
  ```
26
+
27
+ ## Typed Plugin Options
28
+
29
+ You can use a generic type parameter to get fully typed options in your plugins:
30
+
31
+ ```ts
32
+ const { PluginBaseClass } = window;
33
+
34
+ interface MyPluginOptions {
35
+ option1: string;
36
+ option2: number | null;
37
+ }
38
+
39
+ export default class MyPlugin extends PluginBaseClass<MyPluginOptions> {
40
+ static options: MyPluginOptions = {
41
+ option1: 'default value',
42
+ option2: null
43
+ };
44
+
45
+ init() {
46
+ // this.options is fully typed
47
+ console.log(this.options.option1); // string
48
+ console.log(this.options.option2); // number | null
49
+ }
50
+ }
51
+ ```
@@ -27,7 +27,8 @@ interface DomAccessHelper {
27
27
  /**
28
28
  * Returns the selected elements of a defined parent node
29
29
  */
30
- querySelectorAll(element: HTMLElement, selector: string, strict?: boolean): HTMLElement[]
30
+ querySelectorAll(element: HTMLElement, selector: string, strict: true): NodeList
31
+ querySelectorAll(element: HTMLElement, selector: string, strict?: false): NodeList | false
31
32
  }
32
33
 
33
34
  declare module 'src/helper/dom-access.helper' {
package/global.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  declare global {
2
2
  interface Window {
3
3
  PluginManager: import('./plugin-system/plugin-manager').default,
4
- PluginBaseClass: import('./plugin-system/plugin').default,
4
+ PluginBaseClass: typeof import('./plugin-system/plugin').default,
5
5
  router: {
6
6
  'frontend.cart.offcanvas': string,
7
7
  'frontend.cookie.offcanvas': string,
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@shopware-ag/storefront-types",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "Provides Shopware Storefront Typescript types",
5
5
  "types": "index.d.ts",
6
+ "scripts": {
7
+ "test": "tsc --project tsconfig.test.json"
8
+ },
6
9
  "dependencies": {
7
10
  "@types/bootstrap": "^5.2.0"
8
11
  },
@@ -15,6 +15,12 @@ export default interface PluginManager {
15
15
  */
16
16
  extend(fromName: String, newName: string, pluginClass: Object, selector: String | NodeList | HTMLElement, options?: Object): boolean
17
17
 
18
+ /**
19
+ * Overrides an existing plugin with a new class.
20
+ * This is a convenience wrapper around extend() that uses the same name for both fromName and newName.
21
+ */
22
+ override(overrideName: String, pluginClass: Object, selector: String | NodeList | HTMLElement, options?: Object): boolean
23
+
18
24
  /**
19
25
  * Returns a list of all registered plugins.
20
26
  */
@@ -1,19 +1,19 @@
1
1
  import NativeEventEmitter from "./native-event-emitter";
2
2
 
3
- export default interface PluginBaseClass {
4
- new(el: HTMLElement, options?: any, pluginName?: false | string): PluginBaseClass;
3
+ export default class PluginBaseClass<Options extends object = Record<string, unknown>> {
4
+ constructor(el: HTMLElement, options?: Partial<Options>, pluginName?: false | string);
5
5
 
6
6
  el: HTMLElement;
7
7
  $emitter: NativeEventEmitter;
8
8
  _pluginName: String;
9
- initialOptions: object;
10
- options: object;
9
+ initialOptions: Options;
10
+ options: Options;
11
11
  _initialized: boolean;
12
12
  init(): void;
13
13
  _update(): void;
14
14
  update(): void;
15
15
  _registerInstance(): void;
16
16
  _getPluginName(pluginName: false | string): String;
17
- _mergeOptions(options: any): object;
17
+ _mergeOptions(options: Partial<Options>): Options;
18
18
  parseJsonOrFail(dashedPluginName: string): any | string;
19
19
  }
@@ -0,0 +1,38 @@
1
+ // Test case for using window.PluginBaseClass as shown in the issue
2
+ /// <reference path="../global.d.ts" />
3
+
4
+ const { PluginBaseClass } = window;
5
+
6
+ interface MyPluginOptions {
7
+ option1: string;
8
+ option2: number | null;
9
+ }
10
+
11
+ class MyPlugin extends PluginBaseClass<MyPluginOptions> {
12
+ static options: MyPluginOptions = {
13
+ option1: 'default value',
14
+ option2: null,
15
+ };
16
+
17
+ init(): void {
18
+ // Test that instance properties are accessible
19
+ console.log(this.el);
20
+ console.log(this.options);
21
+ console.log(this.$emitter);
22
+
23
+ // Test that options are properly typed
24
+ const opt1: string = this.options.option1;
25
+ const opt2: number | null = this.options.option2;
26
+ }
27
+ }
28
+
29
+ // Test: Can instantiate using the class from window
30
+ const element = document.createElement('div');
31
+ const plugin = new MyPlugin(element, { option1: 'custom' });
32
+
33
+ // Test: Instance properties should be typed correctly
34
+ const opt1: string = plugin.options.option1;
35
+ const opt2: number | null = plugin.options.option2;
36
+
37
+ // @ts-expect-error - Should error when accessing non-existent property
38
+ plugin.options.nonExistent;
@@ -0,0 +1,39 @@
1
+ // Test case for extending PluginBaseClass as shown in the issue
2
+ import PluginBaseClass from '../plugin-system/plugin';
3
+
4
+ interface MyPluginOptions {
5
+ option1: string;
6
+ option2: number | null;
7
+ }
8
+
9
+ class MyPlugin extends PluginBaseClass<MyPluginOptions> {
10
+ static options: MyPluginOptions = {
11
+ option1: 'default value',
12
+ option2: null,
13
+ };
14
+
15
+ init(): void {
16
+ // Test that instance properties are accessible
17
+ console.log(this.el);
18
+ console.log(this.options);
19
+ console.log(this.$emitter);
20
+
21
+ // Test that options are properly typed
22
+ const opt1: string = this.options.option1;
23
+ const opt2: number | null = this.options.option2;
24
+ }
25
+ }
26
+
27
+ // Test: Should be able to instantiate via constructor
28
+ const element = document.createElement('div');
29
+ const plugin = new MyPlugin(element, { option1: 'test' });
30
+
31
+ // Test: Instance properties should be accessible
32
+ const el: HTMLElement = plugin.el;
33
+ const opt1: string = plugin.options.option1;
34
+
35
+ // @ts-expect-error - Should error when accessing non-existent property
36
+ plugin.options.nonExistent;
37
+
38
+ // @ts-expect-error - Should error when assigning wrong type
39
+ const wrongType: number = plugin.options.option1;
@@ -0,0 +1,49 @@
1
+ import type PluginBaseClass from '../plugin-system/plugin';
2
+
3
+ // Test: Generic with custom options type
4
+ interface MyPluginOptions {
5
+ option1: string;
6
+ option2: number | null;
7
+ nested: {
8
+ value: boolean;
9
+ };
10
+ }
11
+
12
+ declare const myPlugin: PluginBaseClass<MyPluginOptions>;
13
+
14
+ // Test: options should be typed correctly
15
+ const opt1: string = myPlugin.options.option1;
16
+ const opt2: number | null = myPlugin.options.option2;
17
+ const nestedVal: boolean = myPlugin.options.nested.value;
18
+
19
+ // Test: initialOptions should also be typed
20
+ const initOpt1: string = myPlugin.initialOptions.option1;
21
+
22
+ // Test: _mergeOptions should accept Partial<Options> and return Options
23
+ const merged: MyPluginOptions = myPlugin._mergeOptions({ option1: 'test' });
24
+ const mergedEmpty: MyPluginOptions = myPlugin._mergeOptions({});
25
+
26
+ // Test: Default generic (backwards compatibility)
27
+ declare const defaultPlugin: PluginBaseClass;
28
+
29
+ // Default plugin options should be Record<string, unknown>
30
+ const defaultOpt: unknown = defaultPlugin.options['anyKey'];
31
+ const defaultInitOpt: unknown = defaultPlugin.initialOptions['anyKey'];
32
+
33
+ // Test: Constructor options parameter should accept Partial<Options>
34
+ declare const PluginClass: new (el: HTMLElement, options?: Partial<MyPluginOptions>, pluginName?: false | string) => PluginBaseClass<MyPluginOptions>;
35
+ declare const element: HTMLElement;
36
+ const instance = new PluginClass(element, { option1: 'partial' });
37
+ const instanceNoOpts = new PluginClass(element);
38
+
39
+ // @ts-expect-error - Should error when accessing non-existent property on typed options
40
+ myPlugin.options.nonExistent;
41
+
42
+ // @ts-expect-error - Should error when assigning wrong type
43
+ const wrongType: number = myPlugin.options.option1;
44
+
45
+ // @ts-expect-error - Should error when passing wrong option type to constructor
46
+ new PluginClass(element, { option1: 123 });
47
+
48
+ // @ts-expect-error - Should error when passing unknown option to constructor
49
+ new PluginClass(element, { unknownOption: 'value' });
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "lib": [
5
+ "es6",
6
+ "DOM"
7
+ ],
8
+ "noImplicitAny": true,
9
+ "noImplicitThis": true,
10
+ "strictNullChecks": true,
11
+ "strictFunctionTypes": true,
12
+ "noEmit": true,
13
+ "forceConsistentCasingInFileNames": true
14
+ },
15
+ "include": [
16
+ "tests/**/*.test-d.ts"
17
+ ]
18
+ }