vrack2-core 1.0.5 → 1.1.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/README.md +8 -2
- package/lib/Bootstrap.js +12 -23
- package/lib/Container.js +179 -201
- package/lib/ImportManager.js +36 -51
- package/lib/MainProcess.js +6 -19
- package/lib/ReactiveRef.d.ts +48 -0
- package/lib/ReactiveRef.js +74 -0
- package/lib/UniversalWorkers.d.ts +59 -0
- package/lib/UniversalWorkers.js +119 -0
- package/lib/Utility.js +11 -15
- package/lib/boot/BootClass.js +1 -12
- package/lib/boot/DeviceFileStorage.js +20 -33
- package/lib/boot/DeviceManager.js +42 -55
- package/lib/boot/StructureStorage.js +20 -35
- package/lib/errors/ErrorManager.js +1 -1
- package/lib/service/Device.js +1 -12
- package/package.json +1 -1
- package/src/ReactiveRef.ts +83 -0
- package/src/UniversalWorkers.ts +127 -0
- package/tsconfig.json +3 -2
|
@@ -22,15 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
27
|
};
|
|
@@ -124,35 +115,33 @@ class DeviceManager extends BootClass_1.default {
|
|
|
124
115
|
*
|
|
125
116
|
* @see IDeivceInfo
|
|
126
117
|
*/
|
|
127
|
-
getDeviceInfo(vendor, device) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return result;
|
|
155
|
-
});
|
|
118
|
+
async getDeviceInfo(vendor, device) {
|
|
119
|
+
const di = [vendor, device].join('.');
|
|
120
|
+
const DeviceClass = await this.get(di);
|
|
121
|
+
const dev = new DeviceClass('1', di, this);
|
|
122
|
+
const result = { actions: {}, metrics: {}, inputs: {}, outputs: {}, options: {}, description: '' };
|
|
123
|
+
try {
|
|
124
|
+
const preOptions = dev.checkOptions();
|
|
125
|
+
for (const oName in preOptions)
|
|
126
|
+
result.options[oName] = preOptions[oName].export();
|
|
127
|
+
const dInputs = dev.inputs();
|
|
128
|
+
for (const iName in dInputs)
|
|
129
|
+
result.inputs[iName] = dInputs[iName].export();
|
|
130
|
+
const dOutputs = dev.outputs();
|
|
131
|
+
for (const oName in dOutputs)
|
|
132
|
+
result.outputs[oName] = dOutputs[oName].export();
|
|
133
|
+
const dActions = dev.actions();
|
|
134
|
+
for (const aName in dActions)
|
|
135
|
+
result.actions[aName] = dActions[aName].export();
|
|
136
|
+
const dMetrics = dev.metrics();
|
|
137
|
+
for (const mName in dMetrics)
|
|
138
|
+
result.metrics[mName] = dMetrics[mName].export();
|
|
139
|
+
result.description = dev.description();
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
throw ErrorManager_1.default.make('DM_GET_INFO_EXCEPTION').setTrace(new Error).add(error);
|
|
143
|
+
}
|
|
144
|
+
return result;
|
|
156
145
|
}
|
|
157
146
|
/**
|
|
158
147
|
* Method for updating the device list
|
|
@@ -226,23 +215,21 @@ class DeviceManager extends BootClass_1.default {
|
|
|
226
215
|
* example "vrack.System" where "vrack" is vendor and "System" is device class
|
|
227
216
|
* @param {string} device Device path string
|
|
228
217
|
*/
|
|
229
|
-
get(device, updateList = true) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
throw ErrorManager_1.default.make('DM_DEVICE_NOT_FOUND', { device });
|
|
245
|
-
});
|
|
218
|
+
async get(device, updateList = true) {
|
|
219
|
+
const p = this.devices.get(device); // return device path or undefined
|
|
220
|
+
if (typeof p === 'string') {
|
|
221
|
+
const deviceClass = await Promise.resolve(`${p}`).then(s => __importStar(require(s))); // try import
|
|
222
|
+
if (deviceClass.default)
|
|
223
|
+
return deviceClass.default;
|
|
224
|
+
}
|
|
225
|
+
// Устройство не найдено, но не исключено что если перестроить дерево
|
|
226
|
+
// вендоров и устройств все будет так же
|
|
227
|
+
// По умолчанию мы попытаемся обновить дерево
|
|
228
|
+
if (updateList) {
|
|
229
|
+
await this.updateDeviceList();
|
|
230
|
+
return await this.get(device, false);
|
|
231
|
+
}
|
|
232
|
+
throw ErrorManager_1.default.make('DM_DEVICE_NOT_FOUND', { device });
|
|
246
233
|
}
|
|
247
234
|
/**
|
|
248
235
|
* Find vendor by name
|
|
@@ -3,15 +3,6 @@
|
|
|
3
3
|
* Copyright © 2024 Boris Bobylev. All rights reserved.
|
|
4
4
|
* Licensed under the Apache License, Version 2.0
|
|
5
5
|
*/
|
|
6
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
9
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
10
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
11
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
12
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
6
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
17
8
|
};
|
|
@@ -59,33 +50,29 @@ class StructureStorage extends BootClass_1.default {
|
|
|
59
50
|
*
|
|
60
51
|
* @see StructureStorage.process
|
|
61
52
|
*/
|
|
62
|
-
beforeLoadedUpdate() {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
});
|
|
53
|
+
async beforeLoadedUpdate() {
|
|
54
|
+
const fp = this.makeFilePath(this.Container.id);
|
|
55
|
+
let structure = {};
|
|
56
|
+
try {
|
|
57
|
+
if ((0, fs_1.existsSync)(fp))
|
|
58
|
+
structure = ImportManager_1.default.importJSON(fp);
|
|
59
|
+
const cStruct = await this.Container.getStructure();
|
|
60
|
+
this.updateStructure(cStruct, structure, this.Container.id);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
this.error(error);
|
|
64
|
+
}
|
|
76
65
|
}
|
|
77
66
|
/**
|
|
78
67
|
* Returns structure by container identifier
|
|
79
68
|
*
|
|
80
69
|
* @param id Container ID
|
|
81
70
|
*/
|
|
82
|
-
getById(id) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return ImportManager_1.default.importJSON(fp);
|
|
88
|
-
});
|
|
71
|
+
async getById(id) {
|
|
72
|
+
const fp = this.makeFilePath(id);
|
|
73
|
+
if (!(0, fs_1.existsSync)(fp))
|
|
74
|
+
throw ErrorManager_1.default.make('SS_STRUCT_NOT_FOUND', { id });
|
|
75
|
+
return ImportManager_1.default.importJSON(fp);
|
|
89
76
|
}
|
|
90
77
|
/**
|
|
91
78
|
* Updating the container structure
|
|
@@ -93,11 +80,9 @@ class StructureStorage extends BootClass_1.default {
|
|
|
93
80
|
* @param id Container ID
|
|
94
81
|
* @param structure updated container structure object
|
|
95
82
|
*/
|
|
96
|
-
updateById(id, structure) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.updateStructure(cStruct, structure, id);
|
|
100
|
-
});
|
|
83
|
+
async updateById(id, structure) {
|
|
84
|
+
const cStruct = await this.getById(id);
|
|
85
|
+
this.updateStructure(cStruct, structure, id);
|
|
101
86
|
}
|
|
102
87
|
/**
|
|
103
88
|
* Updates the display structure parameter from the file structure
|
|
@@ -33,7 +33,7 @@ class ErrorManager {
|
|
|
33
33
|
const reg2 = this.getRegistered(short);
|
|
34
34
|
if (reg1 !== null || reg2 !== null) {
|
|
35
35
|
// Если уже есть идентичная запись - просто игнорим
|
|
36
|
-
if (
|
|
36
|
+
if (reg1?.code === reg2?.code && reg1?.short === reg2?.short) {
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
else {
|
package/lib/service/Device.js
CHANGED
|
@@ -3,15 +3,6 @@
|
|
|
3
3
|
* Copyright © 2022 Boris Bobylev. All rights reserved.
|
|
4
4
|
* Licensed under the Apache License, Version 2.0
|
|
5
5
|
*/
|
|
6
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
9
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
10
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
11
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
12
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
6
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
17
8
|
};
|
|
@@ -195,9 +186,7 @@ class Device {
|
|
|
195
186
|
* Used when there is a need to execute before starting the rack
|
|
196
187
|
* and wait for asynchronous code to execute (initialization of some file databases, etc.)
|
|
197
188
|
*/
|
|
198
|
-
processPromise() {
|
|
199
|
-
return __awaiter(this, void 0, void 0, function* () { return; });
|
|
200
|
-
}
|
|
189
|
+
async processPromise() { return; }
|
|
201
190
|
/**
|
|
202
191
|
* Myby todo?
|
|
203
192
|
*
|
package/package.json
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Простой реактивный ref-аналог (как в Vue 3), но только для объектов.
|
|
3
|
+
* Поддерживает глубокую реактивность вложенных plain-объектов.
|
|
4
|
+
* Массивы НЕ отслеживаются внутри — только при переприсвоении свойства целиком.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const state = new ReactiveRef({ user: { name: 'Alice' }, items: [1, 2] });
|
|
9
|
+
*
|
|
10
|
+
* state.watch(() => console.log('изменилось!'));
|
|
11
|
+
*
|
|
12
|
+
* state.value.user.name = 'Bob'; // вызовет callback
|
|
13
|
+
* state.value.items = [1, 2, 3]; // вызовет callback
|
|
14
|
+
* state.value.items.push(4); // НЕ вызовет (мутация массива)
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export default class ReactiveRef<T extends object> {
|
|
18
|
+
/**
|
|
19
|
+
* Хранимое значение
|
|
20
|
+
*/
|
|
21
|
+
private _value: T;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Калбек для обработки при измении значения
|
|
25
|
+
*/
|
|
26
|
+
private watcher: () => void = () => {};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* При создании иницируем объектом
|
|
30
|
+
*/
|
|
31
|
+
constructor(initialValue: T) {
|
|
32
|
+
this._value = this.makeReactive(initialValue);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Getter value
|
|
37
|
+
*/
|
|
38
|
+
get value(): T {
|
|
39
|
+
return this._value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Назначает обработчик который будет вызван при изменении объекта
|
|
44
|
+
*/
|
|
45
|
+
watch(callback: () => void) {
|
|
46
|
+
this.watcher = callback;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Возвращает true если это простой объект не являющийся массивом или null
|
|
51
|
+
* Null кстати тоже объект внутри JS из-за чего эта проверка очень актуальна
|
|
52
|
+
*/
|
|
53
|
+
private isPlainObject(val: unknown): val is Record<string, unknown> {
|
|
54
|
+
return val !== null && typeof val === 'object' && !Array.isArray(val);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Делает переданный объект (если он объект) реактивным
|
|
59
|
+
* Причем делает свойства объекта тоже реактивными рекурсивно
|
|
60
|
+
*/
|
|
61
|
+
private makeReactive<TObj extends object>(obj: TObj): TObj {
|
|
62
|
+
if ((obj as any).__isReactive) return obj;
|
|
63
|
+
|
|
64
|
+
const handler: ProxyHandler<TObj> = {
|
|
65
|
+
set: (target, key, value) => {
|
|
66
|
+
const oldValue = target[key as keyof TObj];
|
|
67
|
+
const isOwn = Object.prototype.hasOwnProperty.call(target, key);
|
|
68
|
+
|
|
69
|
+
// Рекурсивно реактивизируем только обычные объекты (не массивы!)
|
|
70
|
+
const nextValue = this.isPlainObject(value) ? this.makeReactive(value) : value;
|
|
71
|
+
target[key as keyof TObj] = nextValue;
|
|
72
|
+
// Уведомляем только при изменении значения
|
|
73
|
+
if (!isOwn || oldValue !== nextValue) this.watcher();
|
|
74
|
+
return true;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const proxy = new Proxy(obj, handler);
|
|
79
|
+
(proxy as any).__isReactive = true;
|
|
80
|
+
return proxy;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// UniversalWorker.ts
|
|
2
|
+
import { ChildProcess, fork } from 'child_process';
|
|
3
|
+
import { Worker as WorkerThread, parentPort, workerData, isMainThread } from 'worker_threads';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
type UniversalWorkerOptions = {
|
|
7
|
+
isolated?: boolean;
|
|
8
|
+
scriptPath: string;
|
|
9
|
+
workerData?: any;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default class UniversalWorker {
|
|
13
|
+
|
|
14
|
+
private impl: {
|
|
15
|
+
send: (msg: any) => void;
|
|
16
|
+
on: (event: 'message' | 'exit' | 'error', handler: (...args: any[]) => void) => void;
|
|
17
|
+
kill: () => void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Создает новые воркер
|
|
22
|
+
*
|
|
23
|
+
* Если параметр isolated = true будет создан форк
|
|
24
|
+
* иначе будет использоваться WorkerThread
|
|
25
|
+
*/
|
|
26
|
+
constructor(options: UniversalWorkerOptions) {
|
|
27
|
+
const { isolated = true, scriptPath, workerData } = options;
|
|
28
|
+
|
|
29
|
+
if (isolated) {
|
|
30
|
+
// child_process
|
|
31
|
+
const proc = fork(scriptPath, [], {
|
|
32
|
+
env: { ...process.env, VRACK2_WORKER_DATA: JSON.stringify(workerData) }
|
|
33
|
+
});
|
|
34
|
+
this.impl = {
|
|
35
|
+
send: (msg) => proc.send(msg),
|
|
36
|
+
on: (ev, handler) => proc.on(ev, handler),
|
|
37
|
+
kill: () => proc.kill()
|
|
38
|
+
};
|
|
39
|
+
} else {
|
|
40
|
+
// worker_threads
|
|
41
|
+
const wt = new WorkerThread(scriptPath, { workerData });
|
|
42
|
+
this.impl = {
|
|
43
|
+
send: (msg) => wt.postMessage(msg),
|
|
44
|
+
on: (ev, handler) => {
|
|
45
|
+
if (ev === 'message') wt.on('message', handler);
|
|
46
|
+
else if (ev === 'error') wt.on('error', handler);
|
|
47
|
+
else if (ev === 'exit') wt.on('exit', handler as (code: number) => void);
|
|
48
|
+
},
|
|
49
|
+
kill: () => wt.terminate()
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Отправляет внутрь воркера обхект способный к сериализации
|
|
56
|
+
*/
|
|
57
|
+
send(msg: any): void {
|
|
58
|
+
this.impl.send(msg);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Подписывает на события воркера
|
|
63
|
+
*
|
|
64
|
+
* Доступно только message exit error
|
|
65
|
+
*/
|
|
66
|
+
on(event: 'message' | 'exit' | 'error', handler: (...args: any[]) => void): void {
|
|
67
|
+
this.impl.on(event, handler);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Убивает процесс
|
|
72
|
+
*/
|
|
73
|
+
kill() {
|
|
74
|
+
this.impl.kill();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @see kill
|
|
79
|
+
*/
|
|
80
|
+
terminate() {
|
|
81
|
+
this.impl.kill();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
export type WorkerMessageHandler = (message: any) => void;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Определяет - является ли процесс форкнутым
|
|
90
|
+
* Основанно на проверке метода process.send которая есть только у фокрнутого процесса
|
|
91
|
+
*/
|
|
92
|
+
export const isForked = typeof process.send === 'function';
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Определяет - является ли данный инстанс дочерним - не важно используя worker_threads или fork
|
|
96
|
+
* Проверяет !isMainThread || isForked
|
|
97
|
+
*/
|
|
98
|
+
export const isChild = !isMainThread || isForked;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Получение данных сверху, которые были переданны при создании воркера
|
|
102
|
+
* В случае использования worker_threads - workerData
|
|
103
|
+
* Если же это форк - парсит устаноленнюу переменную окружения VRACK2_WORKER_DATA
|
|
104
|
+
*/
|
|
105
|
+
export function getWorkerData(): any {
|
|
106
|
+
if (!isMainThread) return workerData;
|
|
107
|
+
if (isForked) return JSON.parse(process.env.VRACK2_WORKER_DATA || '{}');
|
|
108
|
+
throw new Error('getWorkerData() called in main process');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Отправка данных наверх в родительский процесс
|
|
113
|
+
*/
|
|
114
|
+
export function sendMessage(message: any): void {
|
|
115
|
+
if (!isMainThread) return parentPort?.postMessage(message);
|
|
116
|
+
if (isForked) { process.send?.(message); return }
|
|
117
|
+
throw new Error('sendMessage() called in main process');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Позволяет подписаться на данные которые приходят сверху
|
|
122
|
+
*/
|
|
123
|
+
export function onMessage(handler: WorkerMessageHandler): void {
|
|
124
|
+
if (!isMainThread) parentPort?.on('message', handler);
|
|
125
|
+
else if (isForked) process.on('message', handler);
|
|
126
|
+
else throw new Error('onMessage() called in main process');
|
|
127
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
|
12
12
|
|
|
13
13
|
/* Language and Environment */
|
|
14
|
-
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
|
14
|
+
// "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
|
15
|
+
"target": "es2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
|
15
16
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
|
16
17
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
|
17
18
|
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
|
|
27
28
|
/* Modules */
|
|
28
29
|
"module": "commonjs", /* Specify what module code is generated. */
|
|
29
|
-
|
|
30
|
+
"rootDir": "./src", /* Specify the root folder within your source files. */
|
|
30
31
|
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
|
31
32
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
|
32
33
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|