@nutin/cli 1.2.3 → 1.3.0

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.
Files changed (69) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/README.md +23 -15
  3. package/lib/index.mjs +7 -4
  4. package/lib/src/context-builder.mjs +35 -0
  5. package/lib/src/file-generator.mjs +26 -126
  6. package/lib/src/git-manager.mjs +1 -1
  7. package/lib/src/json-generator.mjs +31 -0
  8. package/lib/src/package-manager.mjs +21 -18
  9. package/lib/src/project-generator.mjs +53 -0
  10. package/lib/src/prompts.mjs +28 -15
  11. package/lib/src/template-compiler.mjs +1 -1
  12. package/lib/src/utils.mjs +9 -9
  13. package/lib/src/version.mjs +1 -0
  14. package/package.json +1 -1
  15. package/templates/base/.gitignore.hbs +1 -0
  16. package/templates/base/builder.config.js.hbs +7 -0
  17. package/templates/base/src/app/main.ts.hbs +2 -1
  18. package/templates/base/src/app/views/home/home.view.test.js.hbs +26 -0
  19. package/templates/base/src/app/views/home/home.view.ts.hbs +2 -2
  20. package/templates/base/src/app/views/not-found/not-found.view.ts.hbs +1 -1
  21. package/templates/base/src/core/base-classes/base-component/base-component.ts.hbs +23 -20
  22. package/templates/base/src/core/base-classes/base-component/helpers/catalog.helper.ts.hbs +2 -2
  23. package/templates/base/src/core/base-classes/base-component/helpers/children.helper.ts.hbs +4 -4
  24. package/templates/base/src/core/base-classes/base-component/helpers/dom.helper.ts.hbs +26 -13
  25. package/templates/base/src/core/base-classes/base-component/helpers/event.helper.ts.hbs +9 -9
  26. package/templates/base/src/core/base-classes/base-component/helpers/security.helper.ts.hbs +40 -8
  27. package/templates/base/src/core/base-classes/base-component/helpers/token.helper.ts.hbs +16 -16
  28. package/templates/base/src/core/base-classes/component/component.ts.hbs +12 -12
  29. package/templates/base/src/core/base-classes/component/helpers/config.helper.ts.hbs +2 -2
  30. package/templates/base/src/core/base-classes/component/helpers/data-binding.helper.ts.hbs +2 -2
  31. package/templates/base/src/core/base-classes/service/service.ts.hbs +35 -12
  32. package/templates/base/src/core/base-classes/view/view.ts.hbs +6 -6
  33. package/templates/base/src/core/services/event-bus/event-bus.ts.hbs +13 -13
  34. package/templates/base/src/core/services/http-client/helpers/http-builder.helper.ts.hbs +18 -18
  35. package/templates/base/src/core/services/http-client/helpers/http-manager.helper.ts.hbs +24 -24
  36. package/templates/base/src/core/services/http-client/http-client.ts.hbs +19 -19
  37. package/templates/base/src/core/services/pipe-registry/pipe-registry.ts.hbs +6 -6
  38. package/templates/base/src/core/services/router/helpers/navigation-manager.helper.ts.hbs +13 -13
  39. package/templates/base/src/core/services/router/helpers/route-guard-manager.helper.ts.hbs +22 -22
  40. package/templates/base/src/core/services/router/helpers/view-render-manager.helper.ts.hbs +6 -5
  41. package/templates/base/src/core/services/router/router.ts.hbs +45 -45
  42. package/templates/base/src/core/services/store/store.ts.hbs +6 -6
  43. package/templates/base/src/core/utils/anchor-manager/anchor-manager.utils.ts.hbs +6 -8
  44. package/templates/base/src/core/utils/button-manager/button-manager.utils.ts.hbs +9 -11
  45. package/templates/base/src/core/utils/helpers/attributes.helper.ts.hbs +11 -5
  46. package/templates/base/src/libs/pipes/pipes.ts.hbs +1 -1
  47. package/templates/base/src/libs/popover/popover.ts.hbs +48 -48
  48. package/templates/base/src/libs/snackbar/snackbar.ts.hbs +1 -1
  49. package/templates/base/tools/builder/builder.js.hbs +9 -3
  50. package/templates/base/tools/builder/core/add-tags.js.hbs +46 -0
  51. package/templates/base/tools/builder/core/copy-static.js.hbs +35 -35
  52. package/templates/base/tools/builder/core/finalize-build.js.hbs +6 -6
  53. package/templates/base/tools/builder/core/hash-files.js.hbs +52 -0
  54. package/templates/base/tools/builder/core/validate-html.js.hbs +12 -32
  55. package/templates/base/tools/utils/get-files-recursive.js.hbs +17 -8
  56. package/templates/features/deployHelper/tools/builder/core/compress-files.js.hbs +56 -0
  57. package/templates/{base → features/deployHelper}/tools/deployment/Dockerfile.hbs +12 -4
  58. package/templates/{base → features/deployHelper}/tools/deployment/nginx.conf.hbs +30 -2
  59. package/templates/features/i18n/src/core/base-classes/base-component/helpers/i18n.helper.ts.hbs +4 -6
  60. package/templates/features/i18n/src/core/services/i18n/i18n.ts.hbs +38 -47
  61. package/templates/features/stylinNutin/src/styles/core/_utilities.scss.hbs +17 -0
  62. package/templates/features/template/src/app/views/home/home.view.html.hbs +1 -1
  63. package/templates/features/template/tools/builder/core/merge-templates.js.hbs +2 -2
  64. package/templates/features/testinNutin/testin-nutin/core/src/utils/test-queue.js.hbs +2 -2
  65. package/templates/features/testinNutin/testin-nutin/runner.js.hbs +1 -0
  66. package/templates/features/testinNutin/testin-nutin.config.js.hbs +2 -2
  67. package/templates/base/tools/deployment/gzip.conf.hbs +0 -19
  68. package/templates/features/i18n/src/app/views/home/locales/fr.json.hbs +0 -9
  69. /package/templates/{base → features/deployHelper}/.dockerignore.hbs +0 -0
@@ -12,11 +12,21 @@ export interface IRequestConfig {
12
12
  }
13
13
 
14
14
  export class HttpBuilder {
15
- static buildRequestBody(data: unknown): string | undefined {
16
- return data ? JSON.stringify(data) : undefined;
15
+ public static buildRequestOptions(
16
+ method: HttpMethod,
17
+ data: unknown,
18
+ config: IRequestConfig,
19
+ signal: AbortSignal
20
+ ): RequestInit {
21
+ return {
22
+ method,
23
+ headers: config.headers,
24
+ body: this.buildRequestBody(data),
25
+ signal
26
+ };
17
27
  }
18
28
 
19
- static buildRequestUrl(endpoint: string, queryParams?: Record<string, string>): URL {
29
+ public static buildRequestUrl(endpoint: string, queryParams?: Record<string, string>): URL {
20
30
  const url = new URL(endpoint);
21
31
 
22
32
  if (queryParams) {
@@ -26,23 +36,13 @@ export class HttpBuilder {
26
36
  return url;
27
37
  }
28
38
 
29
- static appendQueryParams(url: URL, queryParams: Record<string, string>): void {
39
+ private static buildRequestBody(data: unknown): string | undefined {
40
+ return data ? JSON.stringify(data) : undefined;
41
+ }
42
+
43
+ private static appendQueryParams(url: URL, queryParams: Record<string, string>): void {
30
44
  Object.entries(queryParams).forEach(([key, value]) => {
31
45
  url.searchParams.append(key, value);
32
46
  });
33
47
  }
34
-
35
- static buildRequestOptions(
36
- method: HttpMethod,
37
- data: unknown,
38
- config: IRequestConfig,
39
- signal: AbortSignal
40
- ): RequestInit {
41
- return {
42
- method,
43
- headers: config.headers,
44
- body: this.buildRequestBody(data),
45
- signal
46
- };
47
- }
48
48
  }
@@ -16,7 +16,7 @@ export class HttpError extends Error {
16
16
  }
17
17
 
18
18
  export class HttpManager {
19
- static createAbortController(timeout?: number): IAbortControllerSetup {
19
+ public static createAbortController(timeout?: number): IAbortControllerSetup {
20
20
  const controller = new AbortController();
21
21
  const timeoutId = timeout ?
22
22
  setTimeout(() => controller.abort(), timeout) :
@@ -25,25 +25,13 @@ export class HttpManager {
25
25
  return { controller, timeoutId };
26
26
  }
27
27
 
28
- static async safeParseErrorResponse(response: Response): Promise<unknown> {
29
- try {
30
- return await response.json();
31
- } catch {
32
- return null;
33
- }
34
- }
35
-
36
- static async validateResponse(response: Response): Promise<void> {
28
+ public static async validateResponse(response: Response): Promise<void> {
37
29
  if (!response.ok) {
38
30
  await this.handleResponseError(response);
39
31
  }
40
32
  }
41
-
42
- static isJsonResponse(contentType: string | null): boolean {
43
- return contentType?.includes('application/json') ?? false;
44
- }
45
33
 
46
- static async parseSuccessResponse<T>(response: Response): Promise<T> {
34
+ public static async parseSuccessResponse<T>(response: Response): Promise<T> {
47
35
  const contentType = response.headers.get('content-type');
48
36
 
49
37
  if (this.isJsonResponse(contentType)) {
@@ -53,25 +41,37 @@ export class HttpManager {
53
41
  return await response.text() as unknown as T;
54
42
  }
55
43
 
56
- static isTimeoutError(error: unknown): boolean {
57
- return error instanceof DOMException && error.name === 'AbortError';
58
- }
59
-
60
- static handleRequestError(error: unknown): never {
44
+ public static handleRequestError(error: unknown): never {
61
45
  if (this.isTimeoutError(error)) {
62
46
  throw new Error('Request timed out');
63
47
  }
64
48
  throw error;
65
49
  }
66
50
 
67
- static async handleResponseError(response: Response): Promise<never> {
51
+ public static cleanupTimeout(timeoutId: TimeoutType | null): void {
52
+ if (timeoutId) {
53
+ clearTimeout(timeoutId);
54
+ }
55
+ }
56
+
57
+ private static async handleResponseError(response: Response): Promise<never> {
68
58
  const errorData = await this.safeParseErrorResponse(response);
69
59
  throw new HttpError(response.status, response.statusText, errorData);
70
60
  }
71
61
 
72
- static cleanupTimeout(timeoutId: TimeoutType | null): void {
73
- if (timeoutId) {
74
- clearTimeout(timeoutId);
62
+ private static isJsonResponse(contentType: string | null): boolean {
63
+ return contentType?.includes('application/json') ?? false;
64
+ }
65
+
66
+ private static async safeParseErrorResponse(response: Response): Promise<unknown> {
67
+ try {
68
+ return await response.json();
69
+ } catch {
70
+ return null;
75
71
  }
76
72
  }
73
+
74
+ private static isTimeoutError(error: unknown): boolean {
75
+ return error instanceof DOMException && error.name === 'AbortError';
76
+ }
77
77
  }
@@ -17,15 +17,31 @@ export class HttpClient extends Service<HttpClient> {
17
17
  this._defaultHeaders = { 'Content-Type': 'application/json', ...defaultHeaders };
18
18
  }
19
19
 
20
- public addRequestInterceptor(fn: (url: string, options: RequestInit) => void) {
20
+ public get<T = unknown>(endpoint: string, config?: IRequestConfig): Promise<T> {
21
+ return this.request<T>('GET', endpoint, null, config);
22
+ }
23
+ public post<T = unknown>(endpoint: string, data?: unknown, config?: IRequestConfig): Promise<T> {
24
+ return this.request<T>('POST', endpoint, data, config);
25
+ }
26
+ public put<T = unknown>(endpoint: string, data?: unknown, config?: IRequestConfig): Promise<T> {
27
+ return this.request<T>('PUT', endpoint, data, config);
28
+ }
29
+ public patch<T = unknown>(endpoint: string, data?: unknown, config?: IRequestConfig): Promise<T> {
30
+ return this.request<T>('PATCH', endpoint, data, config);
31
+ }
32
+ public delete<T = unknown>(endpoint: string, config?: IRequestConfig): Promise<T> {
33
+ return this.request<T>('DELETE', endpoint, undefined, config);
34
+ }
35
+
36
+ public addRequestInterceptor(fn: (url: string, options: RequestInit) => void): void {
21
37
  this._requestInterceptors.push(fn);
22
38
  }
23
39
 
24
- public addResponseInterceptor(fn: (response: Response) => void) {
40
+ public addResponseInterceptor(fn: (response: Response) => void): void {
25
41
  this._responseInterceptors.push(fn);
26
42
  }
27
43
 
28
- onDestroy(): void {
44
+ protected onDestroy(): void {
29
45
  this._baseUrl = '';
30
46
  this._defaultHeaders = {};
31
47
  this._requestInterceptors = [];
@@ -60,22 +76,6 @@ export class HttpClient extends Service<HttpClient> {
60
76
  HttpManager.cleanupTimeout(timeoutId);
61
77
  }
62
78
  }
63
-
64
- public get<T = unknown>(endpoint: string, config?: IRequestConfig) {
65
- return this.request<T>('GET', endpoint, null, config);
66
- }
67
- public post<T = unknown>(endpoint: string, data?: unknown, config?: IRequestConfig) {
68
- return this.request<T>('POST', endpoint, data, config);
69
- }
70
- public put<T = unknown>(endpoint: string, data?: unknown, config?: IRequestConfig) {
71
- return this.request<T>('PUT', endpoint, data, config);
72
- }
73
- public patch<T = unknown>(endpoint: string, data?: unknown, config?: IRequestConfig) {
74
- return this.request<T>('PATCH', endpoint, data, config);
75
- }
76
- public delete<T = unknown>(endpoint: string, config?: IRequestConfig) {
77
- return this.request<T>('DELETE', endpoint, undefined, config);
78
- }
79
79
  }
80
80
 
81
81
  export const AppHttpClient = HttpClient.getInstance();
@@ -7,11 +7,7 @@ class PipeRegistry extends Service<PipeRegistry> {
7
7
 
8
8
  constructor() { super(); }
9
9
 
10
- onDestroy() {
11
- this._pipes = {};
12
- }
13
-
14
- register(name: string, fn: PipeFunction): void {
10
+ public register(name: string, fn: PipeFunction): void {
15
11
  if(this._pipes[name]) {
16
12
  console.warn(`Skipping pipe "${name}": A pipe with this name already exists.`);
17
13
  return;
@@ -19,7 +15,7 @@ class PipeRegistry extends Service<PipeRegistry> {
19
15
  this._pipes[name] = fn;
20
16
  }
21
17
 
22
- apply(name: string, value: any, args: string[] = []): string {
18
+ public apply(name: string, value: any, args: string[] = []): string {
23
19
  const pipe = this._pipes[name];
24
20
  if (!pipe) {
25
21
  console.warn(`Pipe "${name}" not found.`);
@@ -27,6 +23,10 @@ class PipeRegistry extends Service<PipeRegistry> {
27
23
  }
28
24
  return pipe(value, ...args);
29
25
  }
26
+
27
+ protected onDestroy(): void {
28
+ this._pipes = {};
29
+ }
30
30
  }
31
31
 
32
32
  export const AppPipeRegistry = PipeRegistry.getInstance();
@@ -4,20 +4,12 @@ import { {{#if i18n}}I18nService, {{/if}}View } from "../../../index.js";
4
4
  * Navigation - handles path normalization and history management
5
5
  */
6
6
  export class NavigationManager {
7
- static normalizePath(path: string): string {
7
+ public static normalizePath(path: string): string {
8
8
  const url = new URL(path, window.location.origin);
9
9
  return (url.pathname || '/').replace(/\/+$/, '') || '/';
10
10
  }
11
11
 
12
- static shouldPushState(
13
- pushState: boolean,
14
- currentPath: string,
15
- normalizedPath: string
16
- ): boolean {
17
- return pushState && currentPath !== normalizedPath;
18
- }
19
-
20
- static updateHistory(
12
+ public static updateHistory(
21
13
  normalizedPath: string,
22
14
  currentPath: string,
23
15
  pushState: boolean
@@ -27,7 +19,7 @@ export class NavigationManager {
27
19
  }
28
20
  }
29
21
 
30
- static updateMetaContent(currentView: View): void {
22
+ public static updateMetaContent(currentView: View): void {
31
23
  if (!currentView.shouldUpdateMetaContent()) return;
32
24
 
33
25
  const strippedName = currentView.viewName.replace('-view', '');
@@ -44,11 +36,11 @@ export class NavigationManager {
44
36
  {{/if}}
45
37
  }
46
38
 
47
- static getCurrentPath(): string {
39
+ public static getCurrentPath(): string {
48
40
  return this.normalizePath(window.location.pathname);
49
41
  }
50
42
 
51
- static matchPattern(pattern: string, path: string): Record<string, string> | null {
43
+ public static matchPattern(pattern: string, path: string): Record<string, string> | null {
52
44
  const paramNames: string[] = [];
53
45
 
54
46
  const regexPattern = pattern
@@ -75,4 +67,12 @@ export class NavigationManager {
75
67
  });
76
68
  return params;
77
69
  }
70
+
71
+ private static shouldPushState(
72
+ pushState: boolean,
73
+ currentPath: string,
74
+ normalizedPath: string
75
+ ): boolean {
76
+ return pushState && currentPath !== normalizedPath;
77
+ }
78
78
  }
@@ -25,31 +25,11 @@ export type RouteConfig = (() => View) | {
25
25
  export type Routes = Record<string, RouteConfig>;
26
26
 
27
27
  export class RouteGuardsManager {
28
- static getViewConstructor(routeConfig: RouteConfig): () => View {
28
+ public static getViewConstructor(routeConfig: RouteConfig): () => View {
29
29
  return typeof routeConfig === 'function' ? routeConfig : routeConfig.view;
30
30
  }
31
31
 
32
- static getRouteGuards(routeConfig: RouteConfig): RouteGuard[] {
33
- return typeof routeConfig === 'function' ? [] : (routeConfig.guards || []);
34
- }
35
-
36
- /**
37
- * Runs all guards in sequence with route parameters and returns the result
38
- */
39
- static async runGuards(
40
- guards: RouteGuard[],
41
- params: Record<string, string>
42
- ): Promise<boolean | string> {
43
- for (const guard of guards) {
44
- const result = await guard(params);
45
- if (result !== true) {
46
- return result; // false or redirect path
47
- }
48
- }
49
- return true;
50
- }
51
-
52
- static async processRouteGuards(
32
+ public static async processRouteGuards(
53
33
  routeConfig: RouteConfig,
54
34
  targetPath: string,
55
35
  params: Record<string, string> = {}
@@ -71,4 +51,24 @@ export class RouteGuardsManager {
71
51
  const viewConstructor = this.getViewConstructor(routeConfig);
72
52
  return { allowed: true, viewConstructor };
73
53
  }
54
+
55
+ private static getRouteGuards(routeConfig: RouteConfig): RouteGuard[] {
56
+ return typeof routeConfig === 'function' ? [] : (routeConfig.guards || []);
57
+ }
58
+
59
+ /**
60
+ * Runs all guards in sequence with route parameters and returns the result
61
+ */
62
+ private static async runGuards(
63
+ guards: RouteGuard[],
64
+ params: Record<string, string>
65
+ ): Promise<boolean | string> {
66
+ for (const guard of guards) {
67
+ const result = await guard(params);
68
+ if (result !== true) {
69
+ return result; // false or redirect path
70
+ }
71
+ }
72
+ return true;
73
+ }
74
74
  }
@@ -5,7 +5,7 @@ import { View, AppEventBus } from '../../../index.js';
5
5
  */
6
6
  export class ViewRenderManager {
7
7
  {{#if transition}}
8
- static renderAnimatedView(view: View): void {
8
+ public static renderAnimatedView(view: View): void {
9
9
  const container = document.getElementById('app');
10
10
  const el = view.render();
11
11
  el.classList.add('app-view-transition');
@@ -17,7 +17,7 @@ export class ViewRenderManager {
17
17
  }
18
18
 
19
19
  {{/if}}
20
- static async transitionOutCurrentView(currentView: View | null): Promise<null> {
20
+ public static async transitionOutCurrentView(currentView: View | null): Promise<null> {
21
21
  if (!currentView) return null;
22
22
  {{#if transition}}
23
23
  const container = document.getElementById('app');
@@ -33,7 +33,7 @@ export class ViewRenderManager {
33
33
  return null;
34
34
  }
35
35
 
36
- static renderNewView(
36
+ public static renderNewView(
37
37
  viewConstructor: () => View,
38
38
  params: Record<string, string> = {}
39
39
  ): View {
@@ -49,13 +49,14 @@ export class ViewRenderManager {
49
49
  view.render();
50
50
 
51
51
  {{/if}}
52
+
52
53
  this.cleanupOptionalContent();
53
54
 
54
55
  this.emitEvent('view-mount', view.viewName);
55
56
  return view;
56
57
  }
57
58
 
58
- static cleanupOptionalContent() {
59
+ public static cleanupOptionalContent(): void {
59
60
  const isEmpty = (el: HTMLElement): boolean => {
60
61
  const attrName = el.dataset.optional?.trim();
61
62
 
@@ -85,7 +86,7 @@ export class ViewRenderManager {
85
86
  });
86
87
  }
87
88
 
88
- static emitEvent(event: EventKey, viewName: string): void {
89
+ private static emitEvent(event: EventKey, viewName: string): void {
89
90
  AppEventBus.emit(event, viewName);
90
91
  }
91
92
  {{#if transition}}
@@ -26,6 +26,51 @@ class Router {
26
26
  this.navigate(NavigationManager.getCurrentPath());
27
27
  }
28
28
 
29
+ public async reload(): Promise<void> {
30
+ const currentRoute = NavigationManager.getCurrentPath();
31
+ await this.navigate(currentRoute, false);
32
+ }
33
+
34
+ public async navigate(path: string | '', pushState: boolean = true): Promise<void> {
35
+ const normalizedPath = NavigationManager.normalizePath(path);
36
+ const currentPath = NavigationManager.getCurrentPath();
37
+
38
+ // Try to match the route with parameters
39
+ const routeMatch = this.matchRoute(normalizedPath);
40
+
41
+ if (!routeMatch) {
42
+ await this.handleNotFound(normalizedPath, currentPath, pushState);
43
+ return;
44
+ }
45
+
46
+ const guardResult = await this.handleGuards(
47
+ normalizedPath,
48
+ routeMatch.route,
49
+ routeMatch.params,
50
+ pushState
51
+ );
52
+
53
+ if (!guardResult) return;
54
+
55
+ this._currentView = await ViewRenderManager.transitionOutCurrentView(this._currentView);
56
+ this._currentParams = routeMatch.params;
57
+ this._currentView = ViewRenderManager.renderNewView(
58
+ guardResult.viewConstructor!,
59
+ routeMatch.params
60
+ );
61
+
62
+ NavigationManager.updateMetaContent(this._currentView);
63
+ NavigationManager.updateHistory(normalizedPath, currentPath, pushState);
64
+ }
65
+
66
+ public getCurrentParams(): Record<string, string> {
67
+ return { ...this._currentParams };
68
+ }
69
+
70
+ public getParam(key: string): string | undefined {
71
+ return this._currentParams[key];
72
+ }
73
+
29
74
  private initializeEventListeners(): void {
30
75
  window.addEventListener('popstate', () => this.handlePopState());
31
76
  AppEventBus.subscribe('navigate', (path: string) => this.navigate(path));
@@ -95,51 +140,6 @@ class Router {
95
140
 
96
141
  return guardResult;
97
142
  }
98
-
99
- public async reload(): Promise<void> {
100
- const currentRoute = NavigationManager.getCurrentPath();
101
- await this.navigate(currentRoute, false);
102
- }
103
-
104
- public async navigate(path: string | '', pushState: boolean = true): Promise<void> {
105
- const normalizedPath = NavigationManager.normalizePath(path);
106
- const currentPath = NavigationManager.getCurrentPath();
107
-
108
- // Try to match the route with parameters
109
- const routeMatch = this.matchRoute(normalizedPath);
110
-
111
- if (!routeMatch) {
112
- await this.handleNotFound(normalizedPath, currentPath, pushState);
113
- return;
114
- }
115
-
116
- const guardResult = await this.handleGuards(
117
- normalizedPath,
118
- routeMatch.route,
119
- routeMatch.params,
120
- pushState
121
- );
122
-
123
- if (!guardResult) return;
124
-
125
- this._currentView = await ViewRenderManager.transitionOutCurrentView(this._currentView);
126
- this._currentParams = routeMatch.params;
127
- this._currentView = ViewRenderManager.renderNewView(
128
- guardResult.viewConstructor!,
129
- routeMatch.params
130
- );
131
-
132
- NavigationManager.updateMetaContent(this._currentView);
133
- NavigationManager.updateHistory(normalizedPath, currentPath, pushState);
134
- }
135
-
136
- public getCurrentParams(): Record<string, string> {
137
- return { ...this._currentParams };
138
- }
139
-
140
- public getParam(key: string): string | undefined {
141
- return this._currentParams[key];
142
- }
143
143
  }
144
144
 
145
145
  export const AppRouter = (routes: Routes) => new Router(routes);
@@ -10,10 +10,6 @@ export class Store extends Service<Store> {
10
10
  this.registerCleanup(this.clear);
11
11
  }
12
12
 
13
- protected onDestroy(): void {
14
- this.clear();
15
- }
16
-
17
13
  public set<T = any>(key: string, value: T): void {
18
14
  this._state[key] = value;
19
15
  AppEventBus.emit(`store:${key}`, value);
@@ -27,12 +23,16 @@ export class Store extends Service<Store> {
27
23
  AppEventBus.subscribe(`store:${key}`, callback);
28
24
  }
29
25
 
26
+ public unsubscribe<T = any>(key: string, callback: (value: T) => void): void {
27
+ AppEventBus.off(`store:${key}`, callback);
28
+ }
29
+
30
30
  public clear(): void {
31
31
  this._state = {};
32
32
  }
33
33
 
34
- public unsubscribe<T = any>(key: string, callback: (value: T) => void): void {
35
- AppEventBus.off(`store:${key}`, callback);
34
+ protected onDestroy(): void {
35
+ this.clear();
36
36
  }
37
37
  }
38
38
 
@@ -3,9 +3,9 @@ import { AttributesHelper, IAttributesConfig } from "../helpers/attributes.helpe
3
3
  /**
4
4
  * ```typescript
5
5
  interface IAttributesConfig {
6
- {{#if i18n}}
6
+ {{#if i18n}}
7
7
  i18nKey?: string;
8
- {{/if}}
8
+ {{/if}}
9
9
  textContent?: string;
10
10
  className?: string;
11
11
  style?: string;
@@ -42,8 +42,8 @@ export class AnchorManager {
42
42
  target.appendChild(container);
43
43
  }
44
44
 
45
- private createAnchorContainer() {
46
- const container = document.createElement('div');
45
+ private createAnchorContainer(): HTMLSpanElement {
46
+ const container = document.createElement('span');
47
47
  const anchor = this.createAnchor();
48
48
 
49
49
  container.appendChild(anchor);
@@ -56,16 +56,14 @@ export class AnchorManager {
56
56
 
57
57
  this.setAnchorRef(anchor);
58
58
 
59
- AttributesHelper.setContent(anchor, this.config);
60
- AttributesHelper.setStyle(anchor, this.config);
61
- AttributesHelper.setPipes(anchor, this.config);
59
+ AttributesHelper.setAttributes(anchor, this.config);
62
60
 
63
61
  this.handleClick(anchor);
64
62
 
65
63
  return anchor;
66
64
  }
67
65
 
68
- private setAnchorRef(anchor: HTMLAnchorElement) {
66
+ private setAnchorRef(anchor: HTMLAnchorElement): void {
69
67
  anchor.setAttribute('href', this.config.href);
70
68
  if (this.config.target) {
71
69
  anchor.setAttribute('target', this.config.target);
@@ -69,19 +69,24 @@ export class ButtonManager {
69
69
  return container;
70
70
  }
71
71
 
72
+ public appendTo(target: HTMLElement): void {
73
+ const container = this.createButtonContainer();
74
+ if (container) {
75
+ target.appendChild(container);
76
+ }
77
+ }
78
+
72
79
  private createButton(config: BaseButton, index: number): HTMLElement {
73
80
  const button = document.createElement('button');
74
81
 
75
- AttributesHelper.setContent(button, config);
76
- AttributesHelper.setStyle(button, config);
77
- AttributesHelper.setPipes(button, config);
82
+ AttributesHelper.setAttributes(button, config);
78
83
 
79
84
  this.setDataEvent(button, index);
80
85
 
81
86
  return button;
82
87
  }
83
88
 
84
- private setDataEvent(button: HTMLButtonElement, index: number) {
89
+ private setDataEvent(button: HTMLButtonElement, index: number): void {
85
90
  button.setAttribute('data-event', `click:onButtonClick_${index}`);
86
91
  }
87
92
 
@@ -95,13 +100,6 @@ export class ButtonManager {
95
100
  };
96
101
  }
97
102
 
98
- public appendTo(target: HTMLElement): void {
99
- const container = this.createButtonContainer();
100
- if (container) {
101
- target.appendChild(container);
102
- }
103
- }
104
-
105
103
  /** Note : doesn't track container
106
104
  */
107
105
  public updateButtons(newButtons: BaseButton[]): void {
@@ -10,21 +10,27 @@ export interface IAttributesConfig {
10
10
  }
11
11
 
12
12
  export class AttributesHelper {
13
- static setContent(element: HTMLElement, config: IAttributesConfig) {
13
+ public static setAttributes(element: HTMLElement, config: IAttributesConfig): void {
14
+ this.setContent(element, config);
15
+ this.setPipes(element, config);
16
+ this.setStyle(element, config);
17
+ }
18
+
19
+ private static setContent(element: HTMLElement, config: IAttributesConfig): void {
14
20
  element.textContent = config.textContent || '';
15
- {{#if i18n}}
21
+ {{#if i18n}}
16
22
  if (config.i18nKey) {
17
23
  element.setAttribute('data-i18n', config.i18nKey);
18
24
  }
19
- {{/if}}
25
+ {{/if}}
20
26
  }
21
27
 
22
- static setPipes(element: HTMLElement, config: IAttributesConfig) {
28
+ private static setPipes(element: HTMLElement, config: IAttributesConfig): void {
23
29
  if (!config.pipes) return;
24
30
  element.setAttribute('data-pipe', config.pipes);
25
31
  }
26
32
 
27
- static setStyle(element: HTMLElement, config: IAttributesConfig) {
33
+ private static setStyle(element: HTMLElement, config: IAttributesConfig): void {
28
34
  const classes = [
29
35
  config.className
30
36
  ].filter(Boolean).join(' ');
@@ -1,6 +1,6 @@
1
1
  import { AppPipeRegistry } from "../../core/index.js";
2
2
 
3
- export const registerPipes = () => {
3
+ export const registerPipes = (): void => {
4
4
  // currency
5
5
  AppPipeRegistry.register('currency', (
6
6
  value: number,