the-best-sort 1.0.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.
- package/LICENCE +12 -0
- package/README.md +203 -0
- package/dist/index.d.ts +199 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +577 -0
- package/package.json +51 -0
package/LICENCE
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
ОБЩЕСТВЕННАЯ ЛИЦЕНЗИЯ "УДАЧИ С ЭТИМ"
|
|
2
|
+
УСЛОВИЯ И ПОЛОЖЕНИЯ ДЛЯ КОПИРОВАНИЯ, РАСПРОСТРАНЕНИЯ И ИЗМЕНЕНИЯ
|
|
3
|
+
|
|
4
|
+
0. Вы можете ДЕЛАТЬ ВСЁ, ЧТО ЗАХОТИТЕ до тех пор, пока ВЫ НЕ ОСТАВЛЯЕТЕ УЛИК
|
|
5
|
+
ДЛЯ НАХОЖДЕНИЯ АВТОРА оригинального продукта, чтобы обвинить его или заставить
|
|
6
|
+
взять на себя ответственность.
|
|
7
|
+
|
|
8
|
+
НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ АВТОРЫ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ЗА ПРЕТЕНЗИИ,
|
|
9
|
+
УБЫТКИ ИЛИ ДРУГИЕ ОТВЕТСТВЕННОСТИ, ПОДНЯТЫЕ ВО ВРЕМЯ КОНТРАКТА И ВЫЗВАННЫЕ
|
|
10
|
+
ПРЯМОЙ ИЛИ КОСВЕННОЙ СВЯЗЬЮ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
|
|
11
|
+
|
|
12
|
+
Удачи, и храни тебя Господь.
|
package/README.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# The Best Sort
|
|
2
|
+
|
|
3
|
+
A comprehensive TypeScript library for array visualization and asynchronous processing using powerful strategy with advanced object-oriented programming patterns and design principles.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Best Sort is a production ready framework that demonstrates the application of multiple OOP design patterns, architectural principles, and advanced TypeScript features to visualize array element processing. The library implements a most powerful sort strategy.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
### Prerequisites
|
|
12
|
+
|
|
13
|
+
- Node.js 18.0.0 or higher
|
|
14
|
+
- npm or yarn
|
|
15
|
+
|
|
16
|
+
### Setup
|
|
17
|
+
|
|
18
|
+
Clone the repository and install dependencies:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm install -D typescript @types/node
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Running the Library
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npm install -D tsx
|
|
28
|
+
npx tsx src/index.ts
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Manual Compilation
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npx tsc src/index.ts --experimentalDecorators --emitDecoratorMetadata
|
|
35
|
+
node the-best-sort.js
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Design Patterns
|
|
39
|
+
|
|
40
|
+
The Best Sort implements multiple design patterns to create a robust and extensible framework, including singleton, factory, builder, facade, decorators, strategy, observer, command invoker and runner.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## Core Components
|
|
44
|
+
|
|
45
|
+
### VisualizableNumber
|
|
46
|
+
|
|
47
|
+
A comparable number wrapper implementing the `IVisualizable` interface:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
const nums =.map(n => new VisualizableNumber(n));
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
### VisualizationContext
|
|
55
|
+
|
|
56
|
+
Manages state and event notifications during visualization:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const context = new VisualizationContext<VisualizableNumber>("Strategy Name");
|
|
60
|
+
context.attach(observer);
|
|
61
|
+
context.emitElementDisplayed(element, index, delay);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### Observers
|
|
66
|
+
|
|
67
|
+
Track visualization events and collect metrics:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const statsObserver = new StatisticsObserver<VisualizableNumber>();
|
|
71
|
+
visualizer.addObserver(statsObserver);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### Configuration Management
|
|
76
|
+
|
|
77
|
+
Control visualization behavior globally:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
ConfigurationManager.getInstance().updateConfig({
|
|
81
|
+
baseDelayMs: 100,
|
|
82
|
+
enableLogging: true,
|
|
83
|
+
showTimestamps: true,
|
|
84
|
+
colorize: true
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## Event Types
|
|
90
|
+
|
|
91
|
+
The library emits the following event types during visualization:
|
|
92
|
+
|
|
93
|
+
- `STARTED` - Visualization has started
|
|
94
|
+
- `ELEMENT_DISPLAYED` - An array element was displayed
|
|
95
|
+
- `COMPLETED` - Visualization has completed
|
|
96
|
+
- `ERROR` - An error occurred during visualization
|
|
97
|
+
|
|
98
|
+
## Performance Metrics
|
|
99
|
+
|
|
100
|
+
`StatisticsObserver` collects the following metrics:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
interface VisualizationStatistics {
|
|
104
|
+
duration: number; // Total duration in milliseconds
|
|
105
|
+
displayedElements: number; // Number of elements displayed
|
|
106
|
+
totalDelay: number; // Sum of all delays
|
|
107
|
+
averageDelay: number; // Average delay per element
|
|
108
|
+
eventCounts: Map<EventType, number>; // Event counts by type
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
## Architecture
|
|
114
|
+
|
|
115
|
+
The library follows a layered architecture:
|
|
116
|
+
|
|
117
|
+
1. **Core Domain** - `VisualizableNumber`, event types, configuration
|
|
118
|
+
2. **Patterns Layer** - Decorators, strategies, factory implementations
|
|
119
|
+
3. **Context Layer** - `VisualizationContext` managing state and notifications
|
|
120
|
+
4. **Observer Layer** - Multiple observer implementations
|
|
121
|
+
5. **Application Layer** - `ArrayVisualizer`, `CommandInvoker`, runners
|
|
122
|
+
6. **Factory Layer** - Strategy and builder creation
|
|
123
|
+
|
|
124
|
+
## TypeScript Features Used
|
|
125
|
+
|
|
126
|
+
- Generics for type-safe implementations
|
|
127
|
+
- Decorators for cross-cutting concerns
|
|
128
|
+
- Abstract classes and interfaces for contracts
|
|
129
|
+
- Union types and enums for type safety
|
|
130
|
+
- Method decorators with property descriptors
|
|
131
|
+
- Readonly types for immutability
|
|
132
|
+
- Object destructuring and spreading
|
|
133
|
+
|
|
134
|
+
## Extending the Library
|
|
135
|
+
|
|
136
|
+
### Creating Custom Observers
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
class CustomObserver<T extends IVisualizable> implements IObserver<T> {
|
|
140
|
+
update(event: VisualizationEvent<T>): void {
|
|
141
|
+
// Custom logic here
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
visualizer.addObserver(new CustomObserver());
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
### Creating Custom Commands
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
class CustomCommand implements ICommand {
|
|
153
|
+
execute(): void {
|
|
154
|
+
// Custom command logic
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
getDescription(): string {
|
|
158
|
+
return "Custom command description";
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
invoker.enqueueCommand(new CustomCommand());
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
### Creating Custom Runners
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
class CustomRunner<T extends IVisualizable>
|
|
170
|
+
extends AbstractVisualizationRunner<T> {
|
|
171
|
+
|
|
172
|
+
protected beforeRun(): void {
|
|
173
|
+
console.log("Before run");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
protected afterRun(): void {
|
|
177
|
+
console.log("After run");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const runner = new CustomRunner<VisualizableNumber>();
|
|
182
|
+
runner.run(array, StrategyType.TIMEOUT_FOREACH);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Requirements
|
|
186
|
+
|
|
187
|
+
- TypeScript 4.7 or higher
|
|
188
|
+
- Node.js 18.0.0 or higher
|
|
189
|
+
- Decorator support enabled in `tsconfig.json`
|
|
190
|
+
|
|
191
|
+
## Limitations
|
|
192
|
+
|
|
193
|
+
- All timing is based on setTimeout, which may be affected by event loop congestion
|
|
194
|
+
- Very large arrays (10,000+) may cause performance degradation
|
|
195
|
+
- setTimeout precision is not guaranteed to be exact at sub-millisecond scales
|
|
196
|
+
|
|
197
|
+
## Contributing
|
|
198
|
+
|
|
199
|
+
Contributions are welcome. Please ensure all code follows the established patterns and includes appropriate type annotations.
|
|
200
|
+
|
|
201
|
+
## Support
|
|
202
|
+
|
|
203
|
+
For issues, questions, or feature requests, please open an issue in the repository.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
interface IVisualizable {
|
|
2
|
+
getValue(): number;
|
|
3
|
+
toString(): string;
|
|
4
|
+
}
|
|
5
|
+
interface IObserver<T> {
|
|
6
|
+
update(event: VisualizationEvent<T>): void;
|
|
7
|
+
}
|
|
8
|
+
interface ISubject<T> {
|
|
9
|
+
attach(observer: IObserver<T>): void;
|
|
10
|
+
detach(observer: IObserver<T>): void;
|
|
11
|
+
notify(event: VisualizationEvent<T>): void;
|
|
12
|
+
}
|
|
13
|
+
declare enum EventType {
|
|
14
|
+
STARTED = "STARTED",
|
|
15
|
+
ELEMENT_DISPLAYED = "ELEMENT_DISPLAYED",
|
|
16
|
+
COMPLETED = "COMPLETED",
|
|
17
|
+
ERROR = "ERROR"
|
|
18
|
+
}
|
|
19
|
+
interface VisualizationEvent<T> {
|
|
20
|
+
type: EventType;
|
|
21
|
+
element?: T;
|
|
22
|
+
index?: number;
|
|
23
|
+
timestamp: number;
|
|
24
|
+
delay?: number;
|
|
25
|
+
metadata?: Record<string, any>;
|
|
26
|
+
}
|
|
27
|
+
interface IVisualizationStrategy<T extends IVisualizable> {
|
|
28
|
+
visualize(array: T[], context: VisualizationContext<T>): void;
|
|
29
|
+
getName(): string;
|
|
30
|
+
getDescription(): string;
|
|
31
|
+
}
|
|
32
|
+
interface IVisualizationStrategyFactory<T extends IVisualizable> {
|
|
33
|
+
createStrategy(type: StrategyType): IVisualizationStrategy<T>;
|
|
34
|
+
registerStrategy(type: StrategyType, strategy: IVisualizationStrategy<T>): void;
|
|
35
|
+
listAvailableStrategies(): string[];
|
|
36
|
+
}
|
|
37
|
+
declare enum StrategyType {
|
|
38
|
+
TIMEOUT_FOREACH = "TIMEOUT_FOREACH"
|
|
39
|
+
}
|
|
40
|
+
interface VisualizationConfig {
|
|
41
|
+
baseDelayMs: number;
|
|
42
|
+
enableLogging: boolean;
|
|
43
|
+
logPrefix: string;
|
|
44
|
+
showTimestamps: boolean;
|
|
45
|
+
colorize: boolean;
|
|
46
|
+
}
|
|
47
|
+
declare class VisualizableNumber implements IVisualizable {
|
|
48
|
+
private readonly value;
|
|
49
|
+
constructor(value: number);
|
|
50
|
+
getValue(): number;
|
|
51
|
+
toString(): string;
|
|
52
|
+
toDetailedString(): string;
|
|
53
|
+
}
|
|
54
|
+
declare class ConfigurationManager {
|
|
55
|
+
private static instance;
|
|
56
|
+
private config;
|
|
57
|
+
private constructor();
|
|
58
|
+
static getInstance(): ConfigurationManager;
|
|
59
|
+
getConfig(): Readonly<VisualizationConfig>;
|
|
60
|
+
updateConfig(partial: Partial<VisualizationConfig>): void;
|
|
61
|
+
resetToDefaults(): void;
|
|
62
|
+
}
|
|
63
|
+
declare function Measure(target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor;
|
|
64
|
+
declare function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor;
|
|
65
|
+
declare function ValidateArray(target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor;
|
|
66
|
+
declare class VisualizationContext<T extends IVisualizable> implements ISubject<T> {
|
|
67
|
+
private strategyName;
|
|
68
|
+
private observers;
|
|
69
|
+
private eventHistory;
|
|
70
|
+
private elementCount;
|
|
71
|
+
constructor(strategyName: string);
|
|
72
|
+
attach(observer: IObserver<T>): void;
|
|
73
|
+
detach(observer: IObserver<T>): void;
|
|
74
|
+
notify(event: VisualizationEvent<T>): void;
|
|
75
|
+
emitStarted(): void;
|
|
76
|
+
emitElementDisplayed(element: T, index: number, delay: number): void;
|
|
77
|
+
emitCompleted(): void;
|
|
78
|
+
emitError(error: Error): void;
|
|
79
|
+
getEventHistory(): VisualizationEvent<T>[];
|
|
80
|
+
getElementCount(): number;
|
|
81
|
+
getStrategyName(): string;
|
|
82
|
+
}
|
|
83
|
+
declare class ConsoleLoggingObserver<T extends IVisualizable> implements IObserver<T> {
|
|
84
|
+
private config;
|
|
85
|
+
update(event: VisualizationEvent<T>): void;
|
|
86
|
+
}
|
|
87
|
+
declare class StatisticsObserver<T extends IVisualizable> implements IObserver<T> {
|
|
88
|
+
private startTime;
|
|
89
|
+
private endTime;
|
|
90
|
+
private displayedElements;
|
|
91
|
+
private totalDelay;
|
|
92
|
+
private events;
|
|
93
|
+
update(event: VisualizationEvent<T>): void;
|
|
94
|
+
getStatistics(): VisualizationStatistics;
|
|
95
|
+
printStatistics(): void;
|
|
96
|
+
reset(): void;
|
|
97
|
+
}
|
|
98
|
+
interface VisualizationStatistics {
|
|
99
|
+
duration: number;
|
|
100
|
+
displayedElements: number;
|
|
101
|
+
totalDelay: number;
|
|
102
|
+
averageDelay: number;
|
|
103
|
+
eventCounts: Map<EventType, number>;
|
|
104
|
+
}
|
|
105
|
+
declare class HistoryObserver<T extends IVisualizable> implements IObserver<T> {
|
|
106
|
+
private history;
|
|
107
|
+
update(event: VisualizationEvent<T>): void;
|
|
108
|
+
getHistory(): Array<{
|
|
109
|
+
event: VisualizationEvent<T>;
|
|
110
|
+
formattedTime: string;
|
|
111
|
+
}>;
|
|
112
|
+
printHistory(): void;
|
|
113
|
+
clear(): void;
|
|
114
|
+
}
|
|
115
|
+
declare abstract class AbstractVisualizationStrategy<T extends IVisualizable> implements IVisualizationStrategy<T> {
|
|
116
|
+
abstract visualize(array: T[], context: VisualizationContext<T>): void;
|
|
117
|
+
abstract getName(): string;
|
|
118
|
+
abstract getDescription(): string;
|
|
119
|
+
protected getConfig(): Readonly<VisualizationConfig>;
|
|
120
|
+
}
|
|
121
|
+
declare class TimeoutForEachStrategy<T extends IVisualizable> extends AbstractVisualizationStrategy<T> {
|
|
122
|
+
visualize(array: T[], context: VisualizationContext<T>): void;
|
|
123
|
+
getName(): string;
|
|
124
|
+
getDescription(): string;
|
|
125
|
+
}
|
|
126
|
+
declare class ConcreteVisualizationStrategyFactory<T extends IVisualizable> implements IVisualizationStrategyFactory<T> {
|
|
127
|
+
private strategies;
|
|
128
|
+
constructor();
|
|
129
|
+
createStrategy(type: StrategyType): IVisualizationStrategy<T>;
|
|
130
|
+
registerStrategy(type: StrategyType, strategy: IVisualizationStrategy<T>): void;
|
|
131
|
+
listAvailableStrategies(): string[];
|
|
132
|
+
hasStrategy(type: StrategyType): boolean;
|
|
133
|
+
}
|
|
134
|
+
declare class VisualizerBuilder<T extends IVisualizable> {
|
|
135
|
+
private array?;
|
|
136
|
+
private strategy?;
|
|
137
|
+
private observers;
|
|
138
|
+
private config?;
|
|
139
|
+
private enableDefaultObservers;
|
|
140
|
+
setArray(array: T[]): this;
|
|
141
|
+
setStrategy(strategy: IVisualizationStrategy<T>): this;
|
|
142
|
+
addObserver(observer: IObserver<T>): this;
|
|
143
|
+
setConfig(config: Partial<VisualizationConfig>): this;
|
|
144
|
+
disableDefaultObservers(): this;
|
|
145
|
+
build(): ArrayVisualizer<T>;
|
|
146
|
+
reset(): this;
|
|
147
|
+
}
|
|
148
|
+
declare class ArrayVisualizer<T extends IVisualizable> {
|
|
149
|
+
private array;
|
|
150
|
+
private strategy;
|
|
151
|
+
private context;
|
|
152
|
+
constructor(array: T[], strategy: IVisualizationStrategy<T>);
|
|
153
|
+
addObserver(observer: IObserver<T>): void;
|
|
154
|
+
removeObserver(observer: IObserver<T>): void;
|
|
155
|
+
execute(): void;
|
|
156
|
+
getContext(): VisualizationContext<T>;
|
|
157
|
+
getEventHistory(): VisualizationEvent<T>[];
|
|
158
|
+
}
|
|
159
|
+
interface ICommand {
|
|
160
|
+
execute(): void;
|
|
161
|
+
getDescription(): string;
|
|
162
|
+
}
|
|
163
|
+
declare class ExecuteVisualizationCommand<T extends IVisualizable> implements ICommand {
|
|
164
|
+
private visualizer;
|
|
165
|
+
constructor(visualizer: ArrayVisualizer<T>);
|
|
166
|
+
execute(): void;
|
|
167
|
+
getDescription(): string;
|
|
168
|
+
}
|
|
169
|
+
declare class UpdateConfigCommand implements ICommand {
|
|
170
|
+
private config;
|
|
171
|
+
constructor(config: Partial<VisualizationConfig>);
|
|
172
|
+
execute(): void;
|
|
173
|
+
getDescription(): string;
|
|
174
|
+
}
|
|
175
|
+
declare class CommandInvoker {
|
|
176
|
+
private commandQueue;
|
|
177
|
+
private executedCommands;
|
|
178
|
+
enqueueCommand(command: ICommand): void;
|
|
179
|
+
executeNext(): void;
|
|
180
|
+
executeAll(): void;
|
|
181
|
+
getQueueSize(): number;
|
|
182
|
+
clearQueue(): void;
|
|
183
|
+
getExecutedCommands(): ICommand[];
|
|
184
|
+
}
|
|
185
|
+
declare abstract class AbstractVisualizationRunner<T extends IVisualizable> {
|
|
186
|
+
run(array: T[], strategyType: StrategyType): void;
|
|
187
|
+
protected abstract beforeRun(): void;
|
|
188
|
+
protected abstract afterRun(): void;
|
|
189
|
+
protected buildVisualizer(builder: VisualizerBuilder<T>, array: T[], strategy: IVisualizationStrategy<T>): ArrayVisualizer<T>;
|
|
190
|
+
protected executeVisualization(visualizer: ArrayVisualizer<T>): void;
|
|
191
|
+
}
|
|
192
|
+
declare class LoggingVisualizationRunner<T extends IVisualizable> extends AbstractVisualizationRunner<T> {
|
|
193
|
+
protected beforeRun(): void;
|
|
194
|
+
protected afterRun(): void;
|
|
195
|
+
}
|
|
196
|
+
declare function demonstrateVisualization(): void;
|
|
197
|
+
declare function demonstrateWithTemplateMethod(): void;
|
|
198
|
+
declare function demonstrateWithCustomConfig(): void;
|
|
199
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var EventType;
|
|
12
|
+
(function (EventType) {
|
|
13
|
+
EventType["STARTED"] = "STARTED";
|
|
14
|
+
EventType["ELEMENT_DISPLAYED"] = "ELEMENT_DISPLAYED";
|
|
15
|
+
EventType["COMPLETED"] = "COMPLETED";
|
|
16
|
+
EventType["ERROR"] = "ERROR";
|
|
17
|
+
})(EventType || (EventType = {}));
|
|
18
|
+
var StrategyType;
|
|
19
|
+
(function (StrategyType) {
|
|
20
|
+
StrategyType["TIMEOUT_FOREACH"] = "TIMEOUT_FOREACH";
|
|
21
|
+
})(StrategyType || (StrategyType = {}));
|
|
22
|
+
class VisualizableNumber {
|
|
23
|
+
constructor(value) {
|
|
24
|
+
this.value = value;
|
|
25
|
+
}
|
|
26
|
+
getValue() {
|
|
27
|
+
return this.value;
|
|
28
|
+
}
|
|
29
|
+
toString() {
|
|
30
|
+
return `${this.value}`;
|
|
31
|
+
}
|
|
32
|
+
toDetailedString() {
|
|
33
|
+
return `VisualizableNumber(${this.value})`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
class ConfigurationManager {
|
|
37
|
+
constructor() {
|
|
38
|
+
this.config = {
|
|
39
|
+
baseDelayMs: 1000,
|
|
40
|
+
enableLogging: true,
|
|
41
|
+
logPrefix: '',
|
|
42
|
+
showTimestamps: false,
|
|
43
|
+
colorize: true
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
static getInstance() {
|
|
47
|
+
if (!ConfigurationManager.instance) {
|
|
48
|
+
ConfigurationManager.instance = new ConfigurationManager();
|
|
49
|
+
}
|
|
50
|
+
return ConfigurationManager.instance;
|
|
51
|
+
}
|
|
52
|
+
getConfig() {
|
|
53
|
+
return Object.freeze({ ...this.config });
|
|
54
|
+
}
|
|
55
|
+
updateConfig(partial) {
|
|
56
|
+
this.config = { ...this.config, ...partial };
|
|
57
|
+
}
|
|
58
|
+
resetToDefaults() {
|
|
59
|
+
this.config = {
|
|
60
|
+
baseDelayMs: 1000,
|
|
61
|
+
enableLogging: true,
|
|
62
|
+
logPrefix: '🎯',
|
|
63
|
+
showTimestamps: false,
|
|
64
|
+
colorize: true
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function Measure(target, propertyKey, descriptor) {
|
|
69
|
+
const originalMethod = descriptor.value;
|
|
70
|
+
descriptor.value = function (...args) {
|
|
71
|
+
const start = performance.now();
|
|
72
|
+
const result = originalMethod.apply(this, args);
|
|
73
|
+
if (result && typeof result.then === 'function') {
|
|
74
|
+
return result.then((res) => {
|
|
75
|
+
const end = performance.now();
|
|
76
|
+
console.log(`${propertyKey} completed in ${(end - start).toFixed(2)}ms`);
|
|
77
|
+
return res;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const end = performance.now();
|
|
81
|
+
console.log(`${propertyKey} executed in ${(end - start).toFixed(2)}ms`);
|
|
82
|
+
return result;
|
|
83
|
+
};
|
|
84
|
+
return descriptor;
|
|
85
|
+
}
|
|
86
|
+
function Log(target, propertyKey, descriptor) {
|
|
87
|
+
const originalMethod = descriptor.value;
|
|
88
|
+
descriptor.value = function (...args) {
|
|
89
|
+
const config = ConfigurationManager.getInstance().getConfig();
|
|
90
|
+
if (config.enableLogging) {
|
|
91
|
+
console.log(`Calling ${propertyKey} with ${args.length} argument(s)`);
|
|
92
|
+
}
|
|
93
|
+
return originalMethod.apply(this, args);
|
|
94
|
+
};
|
|
95
|
+
return descriptor;
|
|
96
|
+
}
|
|
97
|
+
function ValidateArray(target, propertyKey, descriptor) {
|
|
98
|
+
const originalMethod = descriptor.value;
|
|
99
|
+
descriptor.value = function (...args) {
|
|
100
|
+
const array = args[0];
|
|
101
|
+
if (!Array.isArray(array)) {
|
|
102
|
+
throw new TypeError(`${propertyKey} expects an array as first argument`);
|
|
103
|
+
}
|
|
104
|
+
if (array.length === 0) {
|
|
105
|
+
throw new Error(`${propertyKey} cannot work with empty array`);
|
|
106
|
+
}
|
|
107
|
+
return originalMethod.apply(this, args);
|
|
108
|
+
};
|
|
109
|
+
return descriptor;
|
|
110
|
+
}
|
|
111
|
+
class VisualizationContext {
|
|
112
|
+
constructor(strategyName) {
|
|
113
|
+
this.strategyName = strategyName;
|
|
114
|
+
this.observers = new Set();
|
|
115
|
+
this.eventHistory = [];
|
|
116
|
+
this.elementCount = 0;
|
|
117
|
+
}
|
|
118
|
+
attach(observer) {
|
|
119
|
+
this.observers.add(observer);
|
|
120
|
+
}
|
|
121
|
+
detach(observer) {
|
|
122
|
+
this.observers.delete(observer);
|
|
123
|
+
}
|
|
124
|
+
notify(event) {
|
|
125
|
+
this.eventHistory.push(event);
|
|
126
|
+
this.observers.forEach(observer => observer.update(event));
|
|
127
|
+
}
|
|
128
|
+
emitStarted() {
|
|
129
|
+
const event = {
|
|
130
|
+
type: EventType.STARTED,
|
|
131
|
+
timestamp: Date.now(),
|
|
132
|
+
metadata: { strategy: this.strategyName }
|
|
133
|
+
};
|
|
134
|
+
this.notify(event);
|
|
135
|
+
}
|
|
136
|
+
emitElementDisplayed(element, index, delay) {
|
|
137
|
+
this.elementCount++;
|
|
138
|
+
const event = {
|
|
139
|
+
type: EventType.ELEMENT_DISPLAYED,
|
|
140
|
+
element,
|
|
141
|
+
index,
|
|
142
|
+
timestamp: Date.now(),
|
|
143
|
+
delay,
|
|
144
|
+
metadata: { totalDisplayed: this.elementCount }
|
|
145
|
+
};
|
|
146
|
+
this.notify(event);
|
|
147
|
+
}
|
|
148
|
+
emitCompleted() {
|
|
149
|
+
const event = {
|
|
150
|
+
type: EventType.COMPLETED,
|
|
151
|
+
timestamp: Date.now(),
|
|
152
|
+
metadata: {
|
|
153
|
+
strategy: this.strategyName,
|
|
154
|
+
totalElements: this.elementCount
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
this.notify(event);
|
|
158
|
+
}
|
|
159
|
+
emitError(error) {
|
|
160
|
+
const event = {
|
|
161
|
+
type: EventType.ERROR,
|
|
162
|
+
timestamp: Date.now(),
|
|
163
|
+
metadata: { error: error.message }
|
|
164
|
+
};
|
|
165
|
+
this.notify(event);
|
|
166
|
+
}
|
|
167
|
+
getEventHistory() {
|
|
168
|
+
return [...this.eventHistory];
|
|
169
|
+
}
|
|
170
|
+
getElementCount() {
|
|
171
|
+
return this.elementCount;
|
|
172
|
+
}
|
|
173
|
+
getStrategyName() {
|
|
174
|
+
return this.strategyName;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
class ConsoleLoggingObserver {
|
|
178
|
+
constructor() {
|
|
179
|
+
this.config = ConfigurationManager.getInstance().getConfig();
|
|
180
|
+
}
|
|
181
|
+
update(event) {
|
|
182
|
+
if (!this.config.enableLogging)
|
|
183
|
+
return;
|
|
184
|
+
const timestamp = this.config.showTimestamps
|
|
185
|
+
? `[${new Date(event.timestamp).toISOString()}] `
|
|
186
|
+
: '';
|
|
187
|
+
switch (event.type) {
|
|
188
|
+
case EventType.STARTED:
|
|
189
|
+
console.log(`\n${this.config.logPrefix} ${timestamp}Visualization started: ${event.metadata?.strategy}`);
|
|
190
|
+
break;
|
|
191
|
+
case EventType.ELEMENT_DISPLAYED:
|
|
192
|
+
const delayInfo = event.delay ? ` (delay: ${event.delay}ms)` : '';
|
|
193
|
+
console.log(`${this.config.logPrefix} ${timestamp}Element ${event.element?.getValue()} displayed${delayInfo}`);
|
|
194
|
+
break;
|
|
195
|
+
case EventType.COMPLETED:
|
|
196
|
+
console.log(`${this.config.logPrefix} ${timestamp}Visualization completed: ${event.metadata?.totalElements} elements\n`);
|
|
197
|
+
break;
|
|
198
|
+
case EventType.ERROR:
|
|
199
|
+
console.error(`${this.config.logPrefix} ${timestamp}Error: ${event.metadata?.error}`);
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
class StatisticsObserver {
|
|
205
|
+
constructor() {
|
|
206
|
+
this.startTime = 0;
|
|
207
|
+
this.endTime = 0;
|
|
208
|
+
this.displayedElements = 0;
|
|
209
|
+
this.totalDelay = 0;
|
|
210
|
+
this.events = new Map();
|
|
211
|
+
}
|
|
212
|
+
update(event) {
|
|
213
|
+
const currentCount = this.events.get(event.type) || 0;
|
|
214
|
+
this.events.set(event.type, currentCount + 1);
|
|
215
|
+
switch (event.type) {
|
|
216
|
+
case EventType.STARTED:
|
|
217
|
+
this.startTime = event.timestamp;
|
|
218
|
+
break;
|
|
219
|
+
case EventType.ELEMENT_DISPLAYED:
|
|
220
|
+
this.displayedElements++;
|
|
221
|
+
if (event.delay) {
|
|
222
|
+
this.totalDelay += event.delay;
|
|
223
|
+
}
|
|
224
|
+
break;
|
|
225
|
+
case EventType.COMPLETED:
|
|
226
|
+
this.endTime = event.timestamp;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
getStatistics() {
|
|
231
|
+
return {
|
|
232
|
+
duration: this.endTime - this.startTime,
|
|
233
|
+
displayedElements: this.displayedElements,
|
|
234
|
+
totalDelay: this.totalDelay,
|
|
235
|
+
averageDelay: this.displayedElements > 0 ? this.totalDelay / this.displayedElements : 0,
|
|
236
|
+
eventCounts: new Map(this.events)
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
printStatistics() {
|
|
240
|
+
const stats = this.getStatistics();
|
|
241
|
+
console.log('\n Visualization Statistics:');
|
|
242
|
+
console.log(` Duration: ${stats.duration.toFixed(2)}ms`);
|
|
243
|
+
console.log(` Elements Displayed: ${stats.displayedElements}`);
|
|
244
|
+
console.log(` Total Delay: ${stats.totalDelay}ms`);
|
|
245
|
+
console.log(` Average Delay: ${stats.averageDelay.toFixed(2)}ms`);
|
|
246
|
+
console.log(' Event Counts:');
|
|
247
|
+
stats.eventCounts.forEach((count, type) => {
|
|
248
|
+
console.log(` ${type}: ${count}`);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
reset() {
|
|
252
|
+
this.startTime = 0;
|
|
253
|
+
this.endTime = 0;
|
|
254
|
+
this.displayedElements = 0;
|
|
255
|
+
this.totalDelay = 0;
|
|
256
|
+
this.events.clear();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
class HistoryObserver {
|
|
260
|
+
constructor() {
|
|
261
|
+
this.history = [];
|
|
262
|
+
}
|
|
263
|
+
update(event) {
|
|
264
|
+
this.history.push({
|
|
265
|
+
event,
|
|
266
|
+
formattedTime: new Date(event.timestamp).toLocaleTimeString()
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
getHistory() {
|
|
270
|
+
return [...this.history];
|
|
271
|
+
}
|
|
272
|
+
printHistory() {
|
|
273
|
+
console.log('\n Visualization History:');
|
|
274
|
+
this.history.forEach(({ event, formattedTime }, index) => {
|
|
275
|
+
console.log(` ${index + 1}. [${formattedTime}] ${event.type}${event.element ? ` - ${event.element.getValue()}` : ''}`);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
clear() {
|
|
279
|
+
this.history = [];
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
class AbstractVisualizationStrategy {
|
|
283
|
+
getConfig() {
|
|
284
|
+
return ConfigurationManager.getInstance().getConfig();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
class TimeoutForEachStrategy extends AbstractVisualizationStrategy {
|
|
288
|
+
visualize(array, context) {
|
|
289
|
+
context.emitStarted();
|
|
290
|
+
try {
|
|
291
|
+
array.forEach((element, index) => {
|
|
292
|
+
const delayMs = element.getValue();
|
|
293
|
+
setTimeout(() => {
|
|
294
|
+
console.log(element.getValue());
|
|
295
|
+
context.emitElementDisplayed(element, index, delayMs);
|
|
296
|
+
if (index === array.length - 1) {
|
|
297
|
+
setTimeout(() => {
|
|
298
|
+
context.emitCompleted();
|
|
299
|
+
}, 10);
|
|
300
|
+
}
|
|
301
|
+
}, delayMs);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
context.emitError(error);
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
getName() {
|
|
310
|
+
return 'setTimeout + forEach Strategy';
|
|
311
|
+
}
|
|
312
|
+
getDescription() {
|
|
313
|
+
return 'Visualizes array elements using setTimeout with delay equal to element value: arr.forEach((t) => setTimeout(() => console.log(t), t))';
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
__decorate([
|
|
317
|
+
Log,
|
|
318
|
+
ValidateArray,
|
|
319
|
+
Measure,
|
|
320
|
+
__metadata("design:type", Function),
|
|
321
|
+
__metadata("design:paramtypes", [Array, VisualizationContext]),
|
|
322
|
+
__metadata("design:returntype", void 0)
|
|
323
|
+
], TimeoutForEachStrategy.prototype, "visualize", null);
|
|
324
|
+
class ConcreteVisualizationStrategyFactory {
|
|
325
|
+
constructor() {
|
|
326
|
+
this.strategies = new Map();
|
|
327
|
+
this.registerStrategy(StrategyType.TIMEOUT_FOREACH, new TimeoutForEachStrategy());
|
|
328
|
+
}
|
|
329
|
+
createStrategy(type) {
|
|
330
|
+
const strategy = this.strategies.get(type);
|
|
331
|
+
if (!strategy) {
|
|
332
|
+
throw new Error(`Strategy type '${type}' not found. Available: ${this.listAvailableStrategies().join(', ')}`);
|
|
333
|
+
}
|
|
334
|
+
return strategy;
|
|
335
|
+
}
|
|
336
|
+
registerStrategy(type, strategy) {
|
|
337
|
+
this.strategies.set(type, strategy);
|
|
338
|
+
}
|
|
339
|
+
listAvailableStrategies() {
|
|
340
|
+
return Array.from(this.strategies.keys());
|
|
341
|
+
}
|
|
342
|
+
hasStrategy(type) {
|
|
343
|
+
return this.strategies.has(type);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
class VisualizerBuilder {
|
|
347
|
+
constructor() {
|
|
348
|
+
this.observers = [];
|
|
349
|
+
this.enableDefaultObservers = true;
|
|
350
|
+
}
|
|
351
|
+
setArray(array) {
|
|
352
|
+
this.array = array;
|
|
353
|
+
return this;
|
|
354
|
+
}
|
|
355
|
+
setStrategy(strategy) {
|
|
356
|
+
this.strategy = strategy;
|
|
357
|
+
return this;
|
|
358
|
+
}
|
|
359
|
+
addObserver(observer) {
|
|
360
|
+
this.observers.push(observer);
|
|
361
|
+
return this;
|
|
362
|
+
}
|
|
363
|
+
setConfig(config) {
|
|
364
|
+
this.config = config;
|
|
365
|
+
return this;
|
|
366
|
+
}
|
|
367
|
+
disableDefaultObservers() {
|
|
368
|
+
this.enableDefaultObservers = false;
|
|
369
|
+
return this;
|
|
370
|
+
}
|
|
371
|
+
build() {
|
|
372
|
+
if (!this.array) {
|
|
373
|
+
throw new Error('Array is required to build visualizer');
|
|
374
|
+
}
|
|
375
|
+
if (!this.strategy) {
|
|
376
|
+
throw new Error('Strategy is required to build visualizer');
|
|
377
|
+
}
|
|
378
|
+
if (this.config) {
|
|
379
|
+
ConfigurationManager.getInstance().updateConfig(this.config);
|
|
380
|
+
}
|
|
381
|
+
const visualizer = new ArrayVisualizer(this.array, this.strategy);
|
|
382
|
+
if (this.enableDefaultObservers) {
|
|
383
|
+
visualizer.addObserver(new ConsoleLoggingObserver());
|
|
384
|
+
}
|
|
385
|
+
this.observers.forEach(observer => visualizer.addObserver(observer));
|
|
386
|
+
return visualizer;
|
|
387
|
+
}
|
|
388
|
+
reset() {
|
|
389
|
+
this.array = undefined;
|
|
390
|
+
this.strategy = undefined;
|
|
391
|
+
this.observers = [];
|
|
392
|
+
this.config = undefined;
|
|
393
|
+
this.enableDefaultObservers = true;
|
|
394
|
+
return this;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
class ArrayVisualizer {
|
|
398
|
+
constructor(array, strategy) {
|
|
399
|
+
this.array = array;
|
|
400
|
+
this.strategy = strategy;
|
|
401
|
+
this.context = new VisualizationContext(strategy.getName());
|
|
402
|
+
}
|
|
403
|
+
addObserver(observer) {
|
|
404
|
+
this.context.attach(observer);
|
|
405
|
+
}
|
|
406
|
+
removeObserver(observer) {
|
|
407
|
+
this.context.detach(observer);
|
|
408
|
+
}
|
|
409
|
+
execute() {
|
|
410
|
+
console.log('\n' + '='.repeat(70));
|
|
411
|
+
console.log(` ${this.strategy.getName()}`);
|
|
412
|
+
console.log('='.repeat(70));
|
|
413
|
+
console.log(` ${this.strategy.getDescription()}`);
|
|
414
|
+
console.log(` Array: [${this.array.map(x => x.getValue()).join(', ')}]`);
|
|
415
|
+
console.log('='.repeat(70));
|
|
416
|
+
this.strategy.visualize([...this.array], this.context);
|
|
417
|
+
}
|
|
418
|
+
getContext() {
|
|
419
|
+
return this.context;
|
|
420
|
+
}
|
|
421
|
+
getEventHistory() {
|
|
422
|
+
return this.context.getEventHistory();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
__decorate([
|
|
426
|
+
Measure,
|
|
427
|
+
__metadata("design:type", Function),
|
|
428
|
+
__metadata("design:paramtypes", []),
|
|
429
|
+
__metadata("design:returntype", void 0)
|
|
430
|
+
], ArrayVisualizer.prototype, "execute", null);
|
|
431
|
+
class ExecuteVisualizationCommand {
|
|
432
|
+
constructor(visualizer) {
|
|
433
|
+
this.visualizer = visualizer;
|
|
434
|
+
}
|
|
435
|
+
execute() {
|
|
436
|
+
this.visualizer.execute();
|
|
437
|
+
}
|
|
438
|
+
getDescription() {
|
|
439
|
+
return 'Execute array visualization';
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
class UpdateConfigCommand {
|
|
443
|
+
constructor(config) {
|
|
444
|
+
this.config = config;
|
|
445
|
+
}
|
|
446
|
+
execute() {
|
|
447
|
+
ConfigurationManager.getInstance().updateConfig(this.config);
|
|
448
|
+
console.log('Configuration updated');
|
|
449
|
+
}
|
|
450
|
+
getDescription() {
|
|
451
|
+
return 'Update visualization configuration';
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
class CommandInvoker {
|
|
455
|
+
constructor() {
|
|
456
|
+
this.commandQueue = [];
|
|
457
|
+
this.executedCommands = [];
|
|
458
|
+
}
|
|
459
|
+
enqueueCommand(command) {
|
|
460
|
+
this.commandQueue.push(command);
|
|
461
|
+
}
|
|
462
|
+
executeNext() {
|
|
463
|
+
const command = this.commandQueue.shift();
|
|
464
|
+
if (command) {
|
|
465
|
+
console.log(`\n🔧 Executing: ${command.getDescription()}`);
|
|
466
|
+
command.execute();
|
|
467
|
+
this.executedCommands.push(command);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
executeAll() {
|
|
471
|
+
while (this.commandQueue.length > 0) {
|
|
472
|
+
this.executeNext();
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
getQueueSize() {
|
|
476
|
+
return this.commandQueue.length;
|
|
477
|
+
}
|
|
478
|
+
clearQueue() {
|
|
479
|
+
this.commandQueue = [];
|
|
480
|
+
}
|
|
481
|
+
getExecutedCommands() {
|
|
482
|
+
return [...this.executedCommands];
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
class AbstractVisualizationRunner {
|
|
486
|
+
run(array, strategyType) {
|
|
487
|
+
this.beforeRun();
|
|
488
|
+
const factory = new ConcreteVisualizationStrategyFactory();
|
|
489
|
+
const strategy = factory.createStrategy(strategyType);
|
|
490
|
+
const builder = new VisualizerBuilder();
|
|
491
|
+
const visualizer = this.buildVisualizer(builder, array, strategy);
|
|
492
|
+
this.executeVisualization(visualizer);
|
|
493
|
+
this.afterRun();
|
|
494
|
+
}
|
|
495
|
+
buildVisualizer(builder, array, strategy) {
|
|
496
|
+
return builder
|
|
497
|
+
.setArray(array)
|
|
498
|
+
.setStrategy(strategy)
|
|
499
|
+
.build();
|
|
500
|
+
}
|
|
501
|
+
executeVisualization(visualizer) {
|
|
502
|
+
visualizer.execute();
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
class LoggingVisualizationRunner extends AbstractVisualizationRunner {
|
|
506
|
+
beforeRun() {
|
|
507
|
+
console.log('\n Starting visualization process...');
|
|
508
|
+
}
|
|
509
|
+
afterRun() {
|
|
510
|
+
console.log('\n Visualization process completed.');
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function demonstrateVisualization() {
|
|
514
|
+
ConfigurationManager.getInstance().updateConfig({
|
|
515
|
+
enableLogging: true,
|
|
516
|
+
logPrefix: '>',
|
|
517
|
+
showTimestamps: false
|
|
518
|
+
});
|
|
519
|
+
console.log('\n' + '='.repeat(70));
|
|
520
|
+
console.log('ARRAY VISUALIZATION FRAMEWORK');
|
|
521
|
+
console.log(' Using setTimeout + forEach Strategy');
|
|
522
|
+
console.log('='.repeat(70));
|
|
523
|
+
const numbers = [1, 2, 3];
|
|
524
|
+
const visualizableArray = numbers.map(n => new VisualizableNumber(n));
|
|
525
|
+
console.log(`\n Input array: [${numbers.join(', ')}]`);
|
|
526
|
+
console.log(' Each element will be displayed after a delay equal to its value (in milliseconds)\n');
|
|
527
|
+
const factory = new ConcreteVisualizationStrategyFactory();
|
|
528
|
+
const strategy = factory.createStrategy(StrategyType.TIMEOUT_FOREACH);
|
|
529
|
+
const statisticsObserver = new StatisticsObserver();
|
|
530
|
+
const historyObserver = new HistoryObserver();
|
|
531
|
+
const builder = new VisualizerBuilder();
|
|
532
|
+
const visualizer = builder
|
|
533
|
+
.setArray(visualizableArray)
|
|
534
|
+
.setStrategy(strategy)
|
|
535
|
+
.addObserver(statisticsObserver)
|
|
536
|
+
.addObserver(historyObserver)
|
|
537
|
+
.build();
|
|
538
|
+
const invoker = new CommandInvoker();
|
|
539
|
+
const visualizationCommand = new ExecuteVisualizationCommand(visualizer);
|
|
540
|
+
invoker.enqueueCommand(visualizationCommand);
|
|
541
|
+
invoker.executeAll();
|
|
542
|
+
setTimeout(() => {
|
|
543
|
+
console.log('\n' + '─'.repeat(70));
|
|
544
|
+
statisticsObserver.printStatistics();
|
|
545
|
+
historyObserver.printHistory();
|
|
546
|
+
console.log('\n' + '='.repeat(70));
|
|
547
|
+
console.log('DEMONSTRATION COMPLETED');
|
|
548
|
+
console.log('='.repeat(70) + '\n');
|
|
549
|
+
}, 5000);
|
|
550
|
+
}
|
|
551
|
+
function demonstrateWithTemplateMethod() {
|
|
552
|
+
const numbers = [1, 2, 3];
|
|
553
|
+
const visualizableArray = numbers.map(n => new VisualizableNumber(n));
|
|
554
|
+
const runner = new LoggingVisualizationRunner();
|
|
555
|
+
runner.run(visualizableArray, StrategyType.TIMEOUT_FOREACH);
|
|
556
|
+
}
|
|
557
|
+
function demonstrateWithCustomConfig() {
|
|
558
|
+
const numbers = [100, 200, 300];
|
|
559
|
+
const visualizableArray = numbers.map(n => new VisualizableNumber(n));
|
|
560
|
+
const invoker = new CommandInvoker();
|
|
561
|
+
const configCommand = new UpdateConfigCommand({
|
|
562
|
+
logPrefix: '[TIMEOUT_FOREACH FRAMEWORK] ',
|
|
563
|
+
showTimestamps: true
|
|
564
|
+
});
|
|
565
|
+
invoker.enqueueCommand(configCommand);
|
|
566
|
+
const factory = new ConcreteVisualizationStrategyFactory();
|
|
567
|
+
const strategy = factory.createStrategy(StrategyType.TIMEOUT_FOREACH);
|
|
568
|
+
const visualizer = new VisualizerBuilder()
|
|
569
|
+
.setArray(visualizableArray)
|
|
570
|
+
.setStrategy(strategy)
|
|
571
|
+
.build();
|
|
572
|
+
const visualizationCommand = new ExecuteVisualizationCommand(visualizer);
|
|
573
|
+
invoker.enqueueCommand(visualizationCommand);
|
|
574
|
+
invoker.executeAll();
|
|
575
|
+
}
|
|
576
|
+
console.log('\n Starting demonstration...\n');
|
|
577
|
+
demonstrateVisualization();
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "the-best-sort",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Sorting framework basid on best design patterns with the most powerful sort strategies in TypeScript",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"LICENSE",
|
|
10
|
+
"README.md",
|
|
11
|
+
"CHANGELOG.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc --project tsconfig.build.json",
|
|
15
|
+
"clean": "rm -rf dist",
|
|
16
|
+
"prebuild": "npm run clean",
|
|
17
|
+
"prepare": "npm run build",
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"type-check": "tsc --noEmit"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"typescript",
|
|
23
|
+
"sort",
|
|
24
|
+
"design-patterns",
|
|
25
|
+
"visualization",
|
|
26
|
+
"observer-pattern",
|
|
27
|
+
"strategy-pattern",
|
|
28
|
+
"factory-pattern",
|
|
29
|
+
"builder-pattern",
|
|
30
|
+
"async",
|
|
31
|
+
"async-visualization"
|
|
32
|
+
],
|
|
33
|
+
"author": "Danila Grigoriev <danila.sar@yandex.ru> (http://danilasar.ru)",
|
|
34
|
+
"license": "GLWT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/danilasar/the-best-sort.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/danilasar/the-best-sort/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/danilasar/the-best-sort#readme",
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^20.10.0",
|
|
48
|
+
"typescript": "^5.3.0",
|
|
49
|
+
"tsx": "^4.20.6"
|
|
50
|
+
}
|
|
51
|
+
}
|