@elliots/unplugin-typical 0.1.6 → 0.1.8
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/dist/esbuild.d.mts +1 -1
- package/dist/esbuild.mjs +1 -1
- package/dist/farm.d.mts +1 -1
- package/dist/farm.mjs +1 -1
- package/dist/{index-BI1Rh2MC.d.mts → index-cR_y1bPs.d.mts} +12 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/rolldown.d.mts +1 -1
- package/dist/rolldown.mjs +1 -1
- package/dist/rollup.d.mts +1 -1
- package/dist/rollup.mjs +1 -1
- package/dist/rspack.d.mts +1 -1
- package/dist/rspack.mjs +1 -1
- package/dist/src-DfYOX15z.mjs +250 -0
- package/dist/vite.d.mts +1 -1
- package/dist/vite.mjs +1 -1
- package/dist/webpack.d.mts +1 -1
- package/dist/webpack.mjs +1 -1
- package/package.json +2 -2
- package/dist/src-DVJWj1px.mjs +0 -112
package/dist/esbuild.d.mts
CHANGED
package/dist/esbuild.mjs
CHANGED
package/dist/farm.d.mts
CHANGED
package/dist/farm.mjs
CHANGED
|
@@ -18,6 +18,18 @@ interface TypicalConfig {
|
|
|
18
18
|
* Example: ["React.*", "Express.Request", "*.Event"]
|
|
19
19
|
*/
|
|
20
20
|
ignoreTypes?: string[];
|
|
21
|
+
/**
|
|
22
|
+
* Skip validation for DOM types (Document, Element, Node, etc.) and their subclasses.
|
|
23
|
+
* These types have complex Window intersections that typia cannot process.
|
|
24
|
+
* Default: true
|
|
25
|
+
*/
|
|
26
|
+
ignoreDOMTypes?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Validate function parameters and return types at runtime.
|
|
29
|
+
* When enabled, typed function parameters get runtime validation calls injected.
|
|
30
|
+
* Default: true
|
|
31
|
+
*/
|
|
32
|
+
validateFunctions?: boolean;
|
|
21
33
|
}
|
|
22
34
|
//#endregion
|
|
23
35
|
//#region src/core/options.d.ts
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as Options, t as Typical } from "./index-
|
|
1
|
+
import { n as Options, t as Typical } from "./index-cR_y1bPs.mjs";
|
|
2
2
|
export { Options, Typical };
|
package/dist/index.mjs
CHANGED
package/dist/rolldown.d.mts
CHANGED
package/dist/rolldown.mjs
CHANGED
package/dist/rollup.d.mts
CHANGED
package/dist/rollup.mjs
CHANGED
package/dist/rspack.d.mts
CHANGED
package/dist/rspack.mjs
CHANGED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { createUnplugin } from "unplugin";
|
|
2
|
+
import { TypicalTransformer, loadConfig } from "@elliots/typical";
|
|
3
|
+
import { dirname, extname, resolve } from "path";
|
|
4
|
+
import ts from "typescript";
|
|
5
|
+
|
|
6
|
+
//#region src/core/options.ts
|
|
7
|
+
function resolveOptions(options) {
|
|
8
|
+
return {
|
|
9
|
+
include: options.include || [/\.[cm]?[jt]sx?$/],
|
|
10
|
+
exclude: options.exclude || [/node_modules/],
|
|
11
|
+
enforce: "enforce" in options ? options.enforce : "pre",
|
|
12
|
+
typical: options.typical
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/core/timing.ts
|
|
18
|
+
/**
|
|
19
|
+
* Performance instrumentation for tracking build times
|
|
20
|
+
*/
|
|
21
|
+
var BuildTimer = class {
|
|
22
|
+
timings = /* @__PURE__ */ new Map();
|
|
23
|
+
starts = /* @__PURE__ */ new Map();
|
|
24
|
+
start(stage) {
|
|
25
|
+
this.starts.set(stage, performance.now());
|
|
26
|
+
}
|
|
27
|
+
end(stage) {
|
|
28
|
+
const start = this.starts.get(stage);
|
|
29
|
+
if (start !== void 0) {
|
|
30
|
+
const duration = performance.now() - start;
|
|
31
|
+
const existing = this.timings.get(stage) ?? [];
|
|
32
|
+
existing.push(duration);
|
|
33
|
+
this.timings.set(stage, existing);
|
|
34
|
+
this.starts.delete(stage);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
reset() {
|
|
38
|
+
this.timings.clear();
|
|
39
|
+
this.starts.clear();
|
|
40
|
+
}
|
|
41
|
+
report() {
|
|
42
|
+
console.log("\n[unplugin-typical] Build Performance Report:");
|
|
43
|
+
console.log("─".repeat(60));
|
|
44
|
+
const sortedStages = Array.from(this.timings.entries()).sort(([, a], [, b]) => b.reduce((x, y) => x + y, 0) - a.reduce((x, y) => x + y, 0));
|
|
45
|
+
let totalTime = 0;
|
|
46
|
+
for (const [stage, times] of sortedStages) {
|
|
47
|
+
const total = times.reduce((a, b) => a + b, 0);
|
|
48
|
+
const avg = total / times.length;
|
|
49
|
+
const min = Math.min(...times);
|
|
50
|
+
const max = Math.max(...times);
|
|
51
|
+
const count = times.length;
|
|
52
|
+
totalTime += total;
|
|
53
|
+
console.log(`${stage}:`);
|
|
54
|
+
console.log(` Count: ${count}`);
|
|
55
|
+
console.log(` Total: ${total.toFixed(2)}ms`);
|
|
56
|
+
console.log(` Avg: ${avg.toFixed(2)}ms`);
|
|
57
|
+
console.log(` Min: ${min.toFixed(2)}ms`);
|
|
58
|
+
console.log(` Max: ${max.toFixed(2)}ms`);
|
|
59
|
+
}
|
|
60
|
+
console.log("─".repeat(60));
|
|
61
|
+
console.log(`Total transform time: ${totalTime.toFixed(2)}ms`);
|
|
62
|
+
console.log("");
|
|
63
|
+
}
|
|
64
|
+
getTimings() {
|
|
65
|
+
const result = /* @__PURE__ */ new Map();
|
|
66
|
+
for (const [stage, times] of this.timings) {
|
|
67
|
+
const total = times.reduce((a, b) => a + b, 0);
|
|
68
|
+
result.set(stage, {
|
|
69
|
+
count: times.length,
|
|
70
|
+
total,
|
|
71
|
+
avg: total / times.length,
|
|
72
|
+
min: Math.min(...times),
|
|
73
|
+
max: Math.max(...times)
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const buildTimer = new BuildTimer();
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/core/transform.ts
|
|
83
|
+
const TRANSFORM_EXTENSIONS = new Set([
|
|
84
|
+
".ts",
|
|
85
|
+
".tsx",
|
|
86
|
+
".mts",
|
|
87
|
+
".cts"
|
|
88
|
+
]);
|
|
89
|
+
/**
|
|
90
|
+
* Transform a TypeScript file with Typical.
|
|
91
|
+
*
|
|
92
|
+
* Uses a shared ProgramManager for incremental compilation across files.
|
|
93
|
+
*/
|
|
94
|
+
function transformTypia(id, source, config, programManager) {
|
|
95
|
+
buildTimer.start("total-transform");
|
|
96
|
+
const ext = extname(id).toLowerCase();
|
|
97
|
+
if (!TRANSFORM_EXTENSIONS.has(ext)) {
|
|
98
|
+
buildTimer.end("total-transform");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const resolvedId = resolve(id);
|
|
102
|
+
buildTimer.start("get-program");
|
|
103
|
+
const program = programManager.getProgram(resolvedId, source);
|
|
104
|
+
buildTimer.end("get-program");
|
|
105
|
+
buildTimer.start("get-source-file");
|
|
106
|
+
const sourceFile = programManager.getSourceFile(resolvedId);
|
|
107
|
+
buildTimer.end("get-source-file");
|
|
108
|
+
if (!sourceFile) {
|
|
109
|
+
buildTimer.end("total-transform");
|
|
110
|
+
console.warn(`[unplugin-typical] Could not get source file for: ${id}`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
buildTimer.start("create-transformer");
|
|
114
|
+
const transformer = new TypicalTransformer(config, program);
|
|
115
|
+
buildTimer.end("create-transformer");
|
|
116
|
+
buildTimer.start("transform");
|
|
117
|
+
const result = transformer.transform(sourceFile, "js");
|
|
118
|
+
buildTimer.end("transform");
|
|
119
|
+
buildTimer.end("total-transform");
|
|
120
|
+
if (process.env.DEBUG) console.log("[unplugin-typical] Transform output (first 1000 chars):", result.substring(0, 1e3));
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/core/program-manager.ts
|
|
126
|
+
/**
|
|
127
|
+
* Manages a shared TypeScript program across file transformations.
|
|
128
|
+
* This avoids the expensive cost of creating a new program for each file.
|
|
129
|
+
*/
|
|
130
|
+
var ProgramManager = class {
|
|
131
|
+
program;
|
|
132
|
+
compilerOptions;
|
|
133
|
+
sourceContents = /* @__PURE__ */ new Map();
|
|
134
|
+
sourceFileCache = /* @__PURE__ */ new Map();
|
|
135
|
+
host;
|
|
136
|
+
/**
|
|
137
|
+
* Get or create a program with the given source content for a file.
|
|
138
|
+
* Uses incremental compilation to reuse data from previous program.
|
|
139
|
+
*/
|
|
140
|
+
getProgram(id, source) {
|
|
141
|
+
const resolvedId = resolve(id);
|
|
142
|
+
this.sourceContents.set(resolvedId, source);
|
|
143
|
+
this.sourceFileCache.delete(resolvedId);
|
|
144
|
+
if (!this.compilerOptions) {
|
|
145
|
+
buildTimer.start("load-compiler-options");
|
|
146
|
+
this.compilerOptions = this.loadCompilerOptions();
|
|
147
|
+
buildTimer.end("load-compiler-options");
|
|
148
|
+
}
|
|
149
|
+
if (!this.host) this.host = this.createHost();
|
|
150
|
+
const rootFiles = this.program?.getRootFileNames() ?? [];
|
|
151
|
+
const rootFileSet = new Set(rootFiles);
|
|
152
|
+
if (!rootFileSet.has(resolvedId)) rootFileSet.add(resolvedId);
|
|
153
|
+
buildTimer.start("create-program-incremental");
|
|
154
|
+
this.program = ts.createProgram(Array.from(rootFileSet), this.compilerOptions, this.host, this.program);
|
|
155
|
+
buildTimer.end("create-program-incremental");
|
|
156
|
+
return this.program;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get the source file for a given ID from the current program.
|
|
160
|
+
*/
|
|
161
|
+
getSourceFile(id) {
|
|
162
|
+
const resolvedId = resolve(id);
|
|
163
|
+
return this.program?.getSourceFile(resolvedId);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Reset the program manager state (e.g., at build start).
|
|
167
|
+
*/
|
|
168
|
+
reset() {
|
|
169
|
+
this.program = void 0;
|
|
170
|
+
this.sourceContents.clear();
|
|
171
|
+
}
|
|
172
|
+
loadCompilerOptions() {
|
|
173
|
+
const configPath = ts.findConfigFile(process.cwd(), ts.sys.fileExists, "tsconfig.json");
|
|
174
|
+
if (!configPath) return {
|
|
175
|
+
target: ts.ScriptTarget.ES2020,
|
|
176
|
+
module: ts.ModuleKind.ESNext,
|
|
177
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
178
|
+
esModuleInterop: true,
|
|
179
|
+
strict: true
|
|
180
|
+
};
|
|
181
|
+
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
182
|
+
if (configFile.error) throw new Error(ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n"));
|
|
183
|
+
return ts.parseJsonConfigFileContent(configFile.config, ts.sys, dirname(configPath)).options;
|
|
184
|
+
}
|
|
185
|
+
createHost() {
|
|
186
|
+
const baseHost = ts.createCompilerHost(this.compilerOptions);
|
|
187
|
+
const originalGetSourceFile = baseHost.getSourceFile.bind(baseHost);
|
|
188
|
+
return {
|
|
189
|
+
...baseHost,
|
|
190
|
+
getSourceFile: (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
191
|
+
const resolvedFileName = resolve(fileName);
|
|
192
|
+
const virtualContent = this.sourceContents.get(resolvedFileName);
|
|
193
|
+
if (virtualContent !== void 0) {
|
|
194
|
+
const cached = this.sourceFileCache.get(resolvedFileName);
|
|
195
|
+
if (cached && cached.text === virtualContent) return cached;
|
|
196
|
+
const sourceFile = ts.createSourceFile(resolvedFileName, virtualContent, languageVersion, true);
|
|
197
|
+
this.sourceFileCache.set(resolvedFileName, sourceFile);
|
|
198
|
+
return sourceFile;
|
|
199
|
+
}
|
|
200
|
+
const cachedDisk = this.sourceFileCache.get(resolvedFileName);
|
|
201
|
+
if (cachedDisk) return cachedDisk;
|
|
202
|
+
const result = originalGetSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
203
|
+
if (result) this.sourceFileCache.set(resolvedFileName, result);
|
|
204
|
+
return result;
|
|
205
|
+
},
|
|
206
|
+
fileExists: (fileName) => {
|
|
207
|
+
const resolvedFileName = resolve(fileName);
|
|
208
|
+
return this.sourceContents.has(resolvedFileName) || baseHost.fileExists(fileName);
|
|
209
|
+
},
|
|
210
|
+
readFile: (fileName) => {
|
|
211
|
+
const resolvedFileName = resolve(fileName);
|
|
212
|
+
return this.sourceContents.get(resolvedFileName) ?? baseHost.readFile(fileName);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region src/index.ts
|
|
220
|
+
const Typical = createUnplugin((rawOptions = {}) => {
|
|
221
|
+
const options = resolveOptions(rawOptions);
|
|
222
|
+
const typicalConfig = {
|
|
223
|
+
...loadConfig(),
|
|
224
|
+
...options.typical
|
|
225
|
+
};
|
|
226
|
+
const programManager = new ProgramManager();
|
|
227
|
+
return {
|
|
228
|
+
name: "unplugin-typical",
|
|
229
|
+
enforce: options.enforce,
|
|
230
|
+
buildStart() {
|
|
231
|
+
buildTimer.reset();
|
|
232
|
+
programManager.reset();
|
|
233
|
+
},
|
|
234
|
+
buildEnd() {
|
|
235
|
+
if (process.env.DEBUG) buildTimer.report();
|
|
236
|
+
},
|
|
237
|
+
transform: {
|
|
238
|
+
filter: { id: {
|
|
239
|
+
include: options.include,
|
|
240
|
+
exclude: options.exclude
|
|
241
|
+
} },
|
|
242
|
+
handler(code, id) {
|
|
243
|
+
return transformTypia(id, code, typicalConfig, programManager);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
//#endregion
|
|
250
|
+
export { Typical as t };
|
package/dist/vite.d.mts
CHANGED
package/dist/vite.mjs
CHANGED
package/dist/webpack.d.mts
CHANGED
package/dist/webpack.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliots/unplugin-typical",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.8",
|
|
5
5
|
"description": "Unplugin for typical - runtime safe TypeScript transformer",
|
|
6
6
|
"author": "Elliot Shepherd <elliot@jarofworms.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"access": "public"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@elliots/typical": "0.1.
|
|
60
|
+
"@elliots/typical": "0.1.8",
|
|
61
61
|
"unplugin": "^2.3.11"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
package/dist/src-DVJWj1px.mjs
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { createUnplugin } from "unplugin";
|
|
2
|
-
import { TypicalTransformer, loadConfig } from "@elliots/typical";
|
|
3
|
-
import ts from "typescript";
|
|
4
|
-
import { dirname, extname, resolve } from "path";
|
|
5
|
-
|
|
6
|
-
//#region src/core/options.ts
|
|
7
|
-
function resolveOptions(options) {
|
|
8
|
-
return {
|
|
9
|
-
include: options.include || [/\.[cm]?[jt]sx?$/],
|
|
10
|
-
exclude: options.exclude || [/node_modules/],
|
|
11
|
-
enforce: "enforce" in options ? options.enforce : "pre",
|
|
12
|
-
typical: options.typical
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
//#endregion
|
|
17
|
-
//#region src/core/transform.ts
|
|
18
|
-
let cachedCompilerOptions;
|
|
19
|
-
const sourceFileCache = /* @__PURE__ */ new Map();
|
|
20
|
-
const TRANSFORM_EXTENSIONS = new Set([
|
|
21
|
-
".ts",
|
|
22
|
-
".tsx",
|
|
23
|
-
".mts",
|
|
24
|
-
".cts"
|
|
25
|
-
]);
|
|
26
|
-
/**
|
|
27
|
-
* Transform a TypeScript file with Typical.
|
|
28
|
-
*
|
|
29
|
-
* Creates a program per file that includes the provided source content.
|
|
30
|
-
* This ensures the type checker can resolve types for the incoming code.
|
|
31
|
-
*/
|
|
32
|
-
function transformTypia(id, source, config) {
|
|
33
|
-
const ext = extname(id).toLowerCase();
|
|
34
|
-
if (!TRANSFORM_EXTENSIONS.has(ext)) return;
|
|
35
|
-
const { program, sourceFile } = createProgramWithSource(resolve(id), source, getCompilerOptions());
|
|
36
|
-
const result = new TypicalTransformer(config, program).transform(sourceFile, "js");
|
|
37
|
-
if (process.env.DEBUG) console.log("[unplugin-typical] Transform output (first 1000 chars):", result.substring(0, 1e3));
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Get TypeScript compiler options from tsconfig.json (cached)
|
|
42
|
-
*/
|
|
43
|
-
function getCompilerOptions() {
|
|
44
|
-
if (cachedCompilerOptions) return cachedCompilerOptions;
|
|
45
|
-
const configPath = ts.findConfigFile(process.cwd(), ts.sys.fileExists, "tsconfig.json");
|
|
46
|
-
if (!configPath) {
|
|
47
|
-
cachedCompilerOptions = {
|
|
48
|
-
target: ts.ScriptTarget.ES2020,
|
|
49
|
-
module: ts.ModuleKind.ESNext,
|
|
50
|
-
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
51
|
-
esModuleInterop: true,
|
|
52
|
-
strict: true
|
|
53
|
-
};
|
|
54
|
-
return cachedCompilerOptions;
|
|
55
|
-
}
|
|
56
|
-
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
57
|
-
if (configFile.error) throw new Error(ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n"));
|
|
58
|
-
cachedCompilerOptions = ts.parseJsonConfigFileContent(configFile.config, ts.sys, dirname(configPath)).options;
|
|
59
|
-
return cachedCompilerOptions;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Create a TypeScript program with the provided source content.
|
|
63
|
-
* Uses a custom compiler host that:
|
|
64
|
-
* - Returns the provided source for the target file
|
|
65
|
-
* - Caches other source files from disk for reuse
|
|
66
|
-
*/
|
|
67
|
-
function createProgramWithSource(id, source, compilerOptions) {
|
|
68
|
-
const sourceFile = ts.createSourceFile(id, source, compilerOptions.target ?? ts.ScriptTarget.ES2020, true);
|
|
69
|
-
const host = ts.createCompilerHost(compilerOptions);
|
|
70
|
-
const originalGetSourceFile = host.getSourceFile.bind(host);
|
|
71
|
-
host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
72
|
-
const resolvedFileName = resolve(fileName);
|
|
73
|
-
if (resolvedFileName === id) return sourceFile;
|
|
74
|
-
const cached = sourceFileCache.get(resolvedFileName);
|
|
75
|
-
if (cached) return cached;
|
|
76
|
-
const result = originalGetSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
77
|
-
if (result) sourceFileCache.set(resolvedFileName, result);
|
|
78
|
-
return result;
|
|
79
|
-
};
|
|
80
|
-
const program = ts.createProgram([id], compilerOptions, host);
|
|
81
|
-
if (process.env.DEBUG) console.log("[unplugin-typical] Program source files:", program.getSourceFiles().map((sf) => sf.fileName));
|
|
82
|
-
return {
|
|
83
|
-
program,
|
|
84
|
-
sourceFile: program.getSourceFile(id)
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
//#endregion
|
|
89
|
-
//#region src/index.ts
|
|
90
|
-
const Typical = createUnplugin((rawOptions = {}) => {
|
|
91
|
-
const options = resolveOptions(rawOptions);
|
|
92
|
-
const typicalConfig = {
|
|
93
|
-
...loadConfig(),
|
|
94
|
-
...options.typical
|
|
95
|
-
};
|
|
96
|
-
return {
|
|
97
|
-
name: "unplugin-typical",
|
|
98
|
-
enforce: options.enforce,
|
|
99
|
-
transform: {
|
|
100
|
-
filter: { id: {
|
|
101
|
-
include: options.include,
|
|
102
|
-
exclude: options.exclude
|
|
103
|
-
} },
|
|
104
|
-
handler(code, id) {
|
|
105
|
-
return transformTypia(id, code, typicalConfig);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
//#endregion
|
|
112
|
-
export { Typical as t };
|