@elliots/typical 0.2.3 → 0.2.5
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/LICENSE +21 -0
- package/README.md +102 -33
- package/bin/typical +0 -0
- package/dist/src/cli.js +15 -15
- package/dist/src/cli.js.map +1 -1
- package/dist/src/config.d.ts +0 -7
- package/dist/src/config.js +6 -7
- package/dist/src/config.js.map +1 -1
- package/dist/src/esm-loader-register.js +2 -2
- package/dist/src/esm-loader-register.js.map +1 -1
- package/dist/src/esm-loader.js +11 -11
- package/dist/src/esm-loader.js.map +1 -1
- package/dist/src/index.d.ts +5 -5
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/timing.d.ts +18 -11
- package/dist/src/timing.js +39 -51
- package/dist/src/timing.js.map +1 -1
- package/dist/src/transformer.d.ts +3 -3
- package/dist/src/transformer.js +8 -8
- package/dist/src/transformer.js.map +1 -1
- package/package.json +5 -5
- package/src/cli.ts +31 -31
- package/src/config.ts +28 -36
- package/src/esm-loader-register.ts +2 -2
- package/src/esm-loader.ts +26 -26
- package/src/index.ts +5 -5
- package/src/patch-fs.cjs +14 -14
- package/src/timing.ts +43 -57
- package/src/transformer.ts +35 -30
- package/dist/src/cli.typical.ts +0 -136
- package/dist/src/config.typical.ts +0 -287
- package/dist/src/file-filter.d.ts +0 -13
- package/dist/src/file-filter.js +0 -42
- package/dist/src/file-filter.js.map +0 -1
- package/dist/src/program-manager.d.ts +0 -27
- package/dist/src/program-manager.js +0 -121
- package/dist/src/program-manager.js.map +0 -1
- package/dist/src/regex-hoister.d.ts +0 -11
- package/dist/src/regex-hoister.js +0 -150
- package/dist/src/regex-hoister.js.map +0 -1
- package/dist/src/setup.d.ts +0 -2
- package/dist/src/setup.js +0 -20
- package/dist/src/setup.js.map +0 -1
- package/dist/src/source-map.d.ts +0 -78
- package/dist/src/source-map.js +0 -133
- package/dist/src/source-map.js.map +0 -1
- package/dist/src/source-map.typical.ts +0 -216
- package/dist/src/transformer.typical.ts +0 -2552
- package/dist/src/tsc-plugin.d.ts +0 -10
- package/dist/src/tsc-plugin.js +0 -13
- package/dist/src/tsc-plugin.js.map +0 -1
package/dist/src/transformer.js
CHANGED
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
* and validation code generation. This class just manages the lifecycle
|
|
6
6
|
* and communication with the Go process.
|
|
7
7
|
*/
|
|
8
|
-
import { resolve } from
|
|
9
|
-
import { TypicalCompiler } from
|
|
10
|
-
import { loadConfig } from
|
|
8
|
+
import { resolve } from "path";
|
|
9
|
+
import { TypicalCompiler } from "@elliots/typical-compiler";
|
|
10
|
+
import { loadConfig } from "./config.js";
|
|
11
11
|
export class TypicalTransformer {
|
|
12
12
|
config;
|
|
13
13
|
compiler;
|
|
14
14
|
projectHandle = null;
|
|
15
15
|
initPromise = null;
|
|
16
16
|
configFile;
|
|
17
|
-
constructor(config, configFile =
|
|
17
|
+
constructor(config, configFile = "tsconfig.json") {
|
|
18
18
|
this.config = config ?? loadConfig();
|
|
19
19
|
this.configFile = configFile;
|
|
20
20
|
this.compiler = new TypicalCompiler({ cwd: process.cwd() });
|
|
@@ -23,7 +23,7 @@ export class TypicalTransformer {
|
|
|
23
23
|
* Ensure the Go compiler is started and project is loaded.
|
|
24
24
|
* Uses lazy initialization - only starts on first transform.
|
|
25
25
|
*/
|
|
26
|
-
async ensureInitialized() {
|
|
26
|
+
async ensureInitialized(x) {
|
|
27
27
|
if (!this.initPromise) {
|
|
28
28
|
this.initPromise = (async () => {
|
|
29
29
|
await this.compiler.start();
|
|
@@ -39,14 +39,14 @@ export class TypicalTransformer {
|
|
|
39
39
|
* @param mode - Output mode: 'ts' returns TypeScript, 'js' would transpile (not yet supported)
|
|
40
40
|
* @returns Transformed code with validation
|
|
41
41
|
*/
|
|
42
|
-
async transform(fileName, mode =
|
|
43
|
-
if (mode ===
|
|
42
|
+
async transform(fileName, mode = "ts") {
|
|
43
|
+
if (mode === "js") {
|
|
44
44
|
throw new Error('Mode "js" not yet supported - use "ts" and transpile separately');
|
|
45
45
|
}
|
|
46
46
|
await this.ensureInitialized();
|
|
47
47
|
const resolvedPath = resolve(fileName);
|
|
48
48
|
// Pass config options to the Go compiler
|
|
49
|
-
const result = await this.compiler.transformFile(this.projectHandle, resolvedPath, this.config.ignoreTypes, this.config.maxGeneratedFunctions
|
|
49
|
+
const result = await this.compiler.transformFile(this.projectHandle, resolvedPath, this.config.ignoreTypes, this.config.maxGeneratedFunctions);
|
|
50
50
|
return {
|
|
51
51
|
code: result.code,
|
|
52
52
|
map: result.sourceMap ?? null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformer.js","sourceRoot":"","sources":["../../src/transformer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"transformer.js","sourceRoot":"","sources":["../../src/transformer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAyC,MAAM,2BAA2B,CAAC;AAEnG,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,MAAM,OAAO,kBAAkB;IACtB,MAAM,CAAgB;IACrB,QAAQ,CAAkB;IAC1B,aAAa,GAAyB,IAAI,CAAC;IAC3C,WAAW,GAAyB,IAAI,CAAC;IACzC,UAAU,CAAS;IAE3B,YAAY,MAAsB,EAAE,aAAqB,eAAe;QACtE,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,eAAe,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,iBAAiB,CAAC,CAAU;QACxC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,WAAW,GAAG,CAAC,KAAK,IAAI,EAAE;gBAC7B,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;gBAC5B,IAAI,CAAC,aAAa,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACxE,CAAC,CAAC,EAAE,CAAC;QACP,CAAC;QACD,MAAM,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,OAAoB,IAAI;QACxD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;QACrF,CAAC;QAED,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE/B,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvC,yCAAyC;QACzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAC9C,IAAI,CAAC,aAAc,EACnB,YAAY,EACZ,IAAI,CAAC,MAAM,CAAC,WAAW,EACvB,IAAI,CAAC,MAAM,CAAC,qBAAqB,CAClC,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,GAAG,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;SAC9B,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliots/typical",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Runtime safe TypeScript transformer using typia",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"runtime",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"commander": "14.0.2",
|
|
43
|
-
"@elliots/typical-compiler": "0.2.
|
|
43
|
+
"@elliots/typical-compiler": "0.2.5"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "22",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"lint:fix": "oxlint --type-aware --fix",
|
|
62
62
|
"format": "oxfmt",
|
|
63
63
|
"format:check": "oxfmt --check",
|
|
64
|
-
"build": "
|
|
65
|
-
"build:all": "pnpm run build:go:all && pnpm run build:ts",
|
|
64
|
+
"build": "pnpm run build:go:all && pnpm run build:ts",
|
|
66
65
|
"build:go": "cd packages/compiler && npm run build:go",
|
|
67
66
|
"build:go:all": "./scripts/build-binaries.sh",
|
|
68
|
-
"build:ts": "pnpm --filter './packages/*' run build &&
|
|
67
|
+
"build:ts": "pnpm --filter './packages/*' run build && tsc",
|
|
68
|
+
"build:website": "pnpm --filter typical-website run build",
|
|
69
69
|
"dev": "tsc --watch",
|
|
70
70
|
"test": "rm -f test/test.temp.ts && tsc && node --import ./dist/src/esm-loader-register.js --test dist/test/*.test.js",
|
|
71
71
|
"test:coverage": "rm -f test/test.temp.ts && tsc && node --import ./dist/src/esm-loader-register.js --test --experimental-test-coverage dist/test/*.test.js",
|
package/src/cli.ts
CHANGED
|
@@ -1,58 +1,58 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { Command } from
|
|
4
|
-
import * as fs from
|
|
5
|
-
import * as path from
|
|
6
|
-
import { TypicalTransformer } from
|
|
7
|
-
import { loadConfig, validateConfig } from
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { TypicalTransformer } from "./transformer.js";
|
|
7
|
+
import { loadConfig, validateConfig } from "./config.js";
|
|
8
8
|
|
|
9
|
-
const program = new Command()
|
|
9
|
+
const program = new Command();
|
|
10
10
|
|
|
11
|
-
program.name(
|
|
11
|
+
program.name("typical").description("Runtime safe TypeScript transformer").version("0.1.0");
|
|
12
12
|
|
|
13
13
|
program
|
|
14
|
-
.command(
|
|
15
|
-
.description(
|
|
16
|
-
.argument(
|
|
17
|
-
.option(
|
|
18
|
-
.option(
|
|
19
|
-
.option(
|
|
14
|
+
.command("transform")
|
|
15
|
+
.description("Transform a TypeScript file with runtime validation")
|
|
16
|
+
.argument("<file>", "TypeScript file to transform")
|
|
17
|
+
.option("-o, --output <file>", "Output file")
|
|
18
|
+
.option("-c, --config <file>", "Config file path", "typical.json")
|
|
19
|
+
.option("-p, --project <file>", "TypeScript config file path", "tsconfig.json")
|
|
20
20
|
.action(
|
|
21
21
|
async (
|
|
22
22
|
file: string,
|
|
23
23
|
options: {
|
|
24
|
-
output?: string
|
|
25
|
-
config?: string
|
|
26
|
-
project?: string
|
|
24
|
+
output?: string;
|
|
25
|
+
config?: string;
|
|
26
|
+
project?: string;
|
|
27
27
|
},
|
|
28
28
|
) => {
|
|
29
|
-
let transformer: TypicalTransformer | null = null
|
|
29
|
+
let transformer: TypicalTransformer | null = null;
|
|
30
30
|
try {
|
|
31
|
-
const config = validateConfig(loadConfig(options.config))
|
|
32
|
-
transformer = new TypicalTransformer(config, options.project)
|
|
31
|
+
const config = validateConfig(loadConfig(options.config));
|
|
32
|
+
transformer = new TypicalTransformer(config, options.project);
|
|
33
33
|
|
|
34
34
|
if (!fs.existsSync(file)) {
|
|
35
|
-
console.error(`File not found: ${file}`)
|
|
36
|
-
process.exit(1)
|
|
35
|
+
console.error(`File not found: ${file}`);
|
|
36
|
+
process.exit(1);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
console.log(`Transforming ${file}...`)
|
|
40
|
-
const result = await transformer.transform(path.resolve(file),
|
|
39
|
+
console.log(`Transforming ${file}...`);
|
|
40
|
+
const result = await transformer.transform(path.resolve(file), "ts");
|
|
41
41
|
|
|
42
42
|
// Determine output file path
|
|
43
|
-
const outputFile = options.output ? path.resolve(options.output) : file +
|
|
43
|
+
const outputFile = options.output ? path.resolve(options.output) : file + ".transformed.ts";
|
|
44
44
|
|
|
45
|
-
fs.writeFileSync(outputFile, result.code)
|
|
46
|
-
console.log(`Transformed code written to ${outputFile}`)
|
|
45
|
+
fs.writeFileSync(outputFile, result.code);
|
|
46
|
+
console.log(`Transformed code written to ${outputFile}`);
|
|
47
47
|
} catch (error) {
|
|
48
|
-
console.error(
|
|
49
|
-
process.exit(1)
|
|
48
|
+
console.error("Transformation failed:", error);
|
|
49
|
+
process.exit(1);
|
|
50
50
|
} finally {
|
|
51
51
|
if (transformer) {
|
|
52
|
-
await transformer.close()
|
|
52
|
+
await transformer.close();
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
|
-
)
|
|
56
|
+
);
|
|
57
57
|
|
|
58
|
-
program.parse()
|
|
58
|
+
program.parse();
|
package/src/config.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface TypicalDebugConfig {
|
|
2
|
-
writeIntermediateFiles?: boolean
|
|
2
|
+
writeIntermediateFiles?: boolean;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -9,59 +9,52 @@ export interface TypicalSourceMapConfig {
|
|
|
9
9
|
/**
|
|
10
10
|
* Generate source maps. Default: true
|
|
11
11
|
*/
|
|
12
|
-
enabled?: boolean
|
|
12
|
+
enabled?: boolean;
|
|
13
13
|
/**
|
|
14
14
|
* Include original source content in the map. Default: true
|
|
15
15
|
*/
|
|
16
|
-
includeContent?: boolean
|
|
16
|
+
includeContent?: boolean;
|
|
17
17
|
/**
|
|
18
18
|
* Use inline source maps (data URL) instead of external files. Default: false
|
|
19
19
|
*/
|
|
20
|
-
inline?: boolean
|
|
20
|
+
inline?: boolean;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export interface TypicalConfig {
|
|
24
|
-
include?: string[]
|
|
25
|
-
exclude?: string[]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* - 'never': Never hoist, always generate inline validators
|
|
30
|
-
* - 'always': Always hoist validators, even if only used once
|
|
31
|
-
*/
|
|
32
|
-
reusableValidators?: 'auto' | 'never' | 'always'
|
|
33
|
-
validateCasts?: boolean
|
|
34
|
-
hoistRegex?: boolean
|
|
35
|
-
debug?: TypicalDebugConfig
|
|
24
|
+
include?: string[];
|
|
25
|
+
exclude?: string[];
|
|
26
|
+
validateCasts?: boolean;
|
|
27
|
+
hoistRegex?: boolean;
|
|
28
|
+
debug?: TypicalDebugConfig;
|
|
36
29
|
/**
|
|
37
30
|
* Type patterns to skip validation for (supports wildcards).
|
|
38
31
|
* Use this for types that typia cannot process (e.g., React event types).
|
|
39
32
|
* Example: ["React.*", "Express.Request", "*.Event"]
|
|
40
33
|
*/
|
|
41
|
-
ignoreTypes?: string[]
|
|
34
|
+
ignoreTypes?: string[];
|
|
42
35
|
/**
|
|
43
36
|
* Validate function parameters and return types at runtime.
|
|
44
37
|
* When enabled, typed function parameters get runtime validation calls injected.
|
|
45
38
|
* Default: true
|
|
46
39
|
*/
|
|
47
|
-
validateFunctions?: boolean
|
|
40
|
+
validateFunctions?: boolean;
|
|
48
41
|
/**
|
|
49
42
|
* Transform JSON.parse<T>() calls to validate and filter the parsed result
|
|
50
43
|
* to only include properties defined in type T.
|
|
51
44
|
* Default: true
|
|
52
45
|
*/
|
|
53
|
-
transformJSONParse?: boolean
|
|
46
|
+
transformJSONParse?: boolean;
|
|
54
47
|
/**
|
|
55
48
|
* Transform JSON.stringify<T>() calls to only stringify properties defined
|
|
56
49
|
* in type T, preventing accidental data leaks.
|
|
57
50
|
* Default: true
|
|
58
51
|
*/
|
|
59
|
-
transformJSONStringify?: boolean
|
|
52
|
+
transformJSONStringify?: boolean;
|
|
60
53
|
/**
|
|
61
54
|
* Source map generation settings.
|
|
62
55
|
* Controls whether and how source maps are generated for transformed code.
|
|
63
56
|
*/
|
|
64
|
-
sourceMap?: TypicalSourceMapConfig
|
|
57
|
+
sourceMap?: TypicalSourceMapConfig;
|
|
65
58
|
/**
|
|
66
59
|
* Maximum number of helper functions (_io0, _io1, etc.) that can be generated
|
|
67
60
|
* for a single type before erroring. Complex DOM types or library types can
|
|
@@ -69,13 +62,12 @@ export interface TypicalConfig {
|
|
|
69
62
|
* Set to 0 to disable the limit.
|
|
70
63
|
* Default: 50
|
|
71
64
|
*/
|
|
72
|
-
maxGeneratedFunctions?: number
|
|
65
|
+
maxGeneratedFunctions?: number;
|
|
73
66
|
}
|
|
74
67
|
|
|
75
68
|
export const defaultConfig: TypicalConfig = {
|
|
76
|
-
include: [
|
|
77
|
-
exclude: [
|
|
78
|
-
reusableValidators: 'auto', // Hoists validators to module scope for reduced code size
|
|
69
|
+
include: ["**/*.ts", "**/*.tsx"],
|
|
70
|
+
exclude: ["node_modules/**", "**/*.d.ts", "dist/**", "build/**"],
|
|
79
71
|
validateCasts: false,
|
|
80
72
|
validateFunctions: true,
|
|
81
73
|
transformJSONParse: true,
|
|
@@ -89,30 +81,30 @@ export const defaultConfig: TypicalConfig = {
|
|
|
89
81
|
includeContent: true,
|
|
90
82
|
inline: false,
|
|
91
83
|
},
|
|
92
|
-
}
|
|
84
|
+
};
|
|
93
85
|
|
|
94
|
-
import fs from
|
|
95
|
-
import path from
|
|
86
|
+
import fs from "fs";
|
|
87
|
+
import path from "path";
|
|
96
88
|
|
|
97
89
|
export function loadConfig(configPath?: string): TypicalConfig {
|
|
98
|
-
const configFile = configPath || path.join(process.cwd(),
|
|
90
|
+
const configFile = configPath || path.join(process.cwd(), "typical.json");
|
|
99
91
|
|
|
100
92
|
if (fs.existsSync(configFile)) {
|
|
101
93
|
try {
|
|
102
|
-
const configContent = fs.readFileSync(configFile,
|
|
103
|
-
const userConfig: Partial<TypicalConfig> = JSON.parse(configContent)
|
|
94
|
+
const configContent = fs.readFileSync(configFile, "utf8");
|
|
95
|
+
const userConfig: Partial<TypicalConfig> = JSON.parse(configContent);
|
|
104
96
|
|
|
105
97
|
return {
|
|
106
98
|
...defaultConfig,
|
|
107
99
|
...userConfig,
|
|
108
|
-
}
|
|
100
|
+
};
|
|
109
101
|
} catch (error) {
|
|
110
|
-
console.warn(`Failed to parse config file ${configFile}:`, error)
|
|
111
|
-
return defaultConfig
|
|
102
|
+
console.warn(`Failed to parse config file ${configFile}:`, error);
|
|
103
|
+
return defaultConfig;
|
|
112
104
|
}
|
|
113
105
|
}
|
|
114
106
|
|
|
115
|
-
return defaultConfig
|
|
107
|
+
return defaultConfig;
|
|
116
108
|
}
|
|
117
109
|
|
|
118
110
|
/**
|
|
@@ -124,5 +116,5 @@ export function loadConfig(configPath?: string): TypicalConfig {
|
|
|
124
116
|
export function validateConfig(config: TypicalConfig): TypicalConfig {
|
|
125
117
|
// Reusable validators now throw at the call site, so they work correctly
|
|
126
118
|
// with source maps. No need for special handling.
|
|
127
|
-
return config
|
|
119
|
+
return config;
|
|
128
120
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { register } from
|
|
2
|
-
register(
|
|
1
|
+
import { register } from "node:module";
|
|
2
|
+
register("./esm-loader.js", { parentURL: import.meta.url });
|
package/src/esm-loader.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { fileURLToPath, pathToFileURL } from
|
|
2
|
-
import { existsSync } from
|
|
3
|
-
import { TypicalTransformer } from
|
|
4
|
-
import { loadConfig, validateConfig } from
|
|
1
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { TypicalTransformer } from "./transformer.js";
|
|
4
|
+
import { loadConfig, validateConfig } from "./config.js";
|
|
5
5
|
|
|
6
|
-
const config = validateConfig(loadConfig())
|
|
6
|
+
const config = validateConfig(loadConfig());
|
|
7
7
|
|
|
8
8
|
// Shared transformer - stays alive for the lifetime of the process
|
|
9
|
-
let transformer: TypicalTransformer | null = null
|
|
9
|
+
let transformer: TypicalTransformer | null = null;
|
|
10
10
|
|
|
11
11
|
async function getTransformer(): Promise<TypicalTransformer> {
|
|
12
12
|
if (!transformer) {
|
|
13
|
-
transformer = new TypicalTransformer(config)
|
|
13
|
+
transformer = new TypicalTransformer(config);
|
|
14
14
|
}
|
|
15
|
-
return transformer
|
|
15
|
+
return transformer;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -20,23 +20,23 @@ async function getTransformer(): Promise<TypicalTransformer> {
|
|
|
20
20
|
*/
|
|
21
21
|
export async function resolve(specifier: string, context: any, nextResolve: any) {
|
|
22
22
|
// Only handle relative imports ending in .js
|
|
23
|
-
if (specifier.startsWith(
|
|
24
|
-
const { parentURL } = context
|
|
23
|
+
if (specifier.startsWith(".") && specifier.endsWith(".js")) {
|
|
24
|
+
const { parentURL } = context;
|
|
25
25
|
if (parentURL) {
|
|
26
|
-
const parentPath = fileURLToPath(parentURL)
|
|
27
|
-
const dir = parentPath.substring(0, parentPath.lastIndexOf(
|
|
28
|
-
const tsPath = dir +
|
|
26
|
+
const parentPath = fileURLToPath(parentURL);
|
|
27
|
+
const dir = parentPath.substring(0, parentPath.lastIndexOf("/"));
|
|
28
|
+
const tsPath = dir + "/" + specifier.slice(0, -3) + ".ts";
|
|
29
29
|
|
|
30
30
|
if (existsSync(tsPath)) {
|
|
31
31
|
return {
|
|
32
32
|
url: pathToFileURL(tsPath).href,
|
|
33
33
|
shortCircuit: true,
|
|
34
|
-
}
|
|
34
|
+
};
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
return nextResolve(specifier, context)
|
|
39
|
+
return nextResolve(specifier, context);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
@@ -44,19 +44,19 @@ export async function resolve(specifier: string, context: any, nextResolve: any)
|
|
|
44
44
|
* Note: Source maps not yet supported in v2
|
|
45
45
|
*/
|
|
46
46
|
export async function load(url: string, context: any, nextLoad: any) {
|
|
47
|
-
if (!url.endsWith(
|
|
48
|
-
return nextLoad(url, context)
|
|
47
|
+
if (!url.endsWith(".ts")) {
|
|
48
|
+
return nextLoad(url, context);
|
|
49
49
|
}
|
|
50
|
-
const filePath = fileURLToPath(url)
|
|
50
|
+
const filePath = fileURLToPath(url);
|
|
51
51
|
|
|
52
52
|
try {
|
|
53
|
-
const t = await getTransformer()
|
|
54
|
-
const result = await t.transform(filePath,
|
|
53
|
+
const t = await getTransformer();
|
|
54
|
+
const result = await t.transform(filePath, "ts");
|
|
55
55
|
|
|
56
56
|
// For now, output is TypeScript - need to transpile to JS
|
|
57
57
|
// TODO: Add JS transpilation in Go or here
|
|
58
58
|
// For now, use TypeScript's transpileModule as fallback
|
|
59
|
-
const ts = await import(
|
|
59
|
+
const ts = await import("typescript");
|
|
60
60
|
const transpiled = ts.default.transpileModule(result.code, {
|
|
61
61
|
compilerOptions: {
|
|
62
62
|
module: ts.default.ModuleKind.ESNext,
|
|
@@ -64,15 +64,15 @@ export async function load(url: string, context: any, nextLoad: any) {
|
|
|
64
64
|
esModuleInterop: true,
|
|
65
65
|
},
|
|
66
66
|
fileName: filePath,
|
|
67
|
-
})
|
|
67
|
+
});
|
|
68
68
|
|
|
69
69
|
return {
|
|
70
|
-
format:
|
|
70
|
+
format: "module",
|
|
71
71
|
source: transpiled.outputText,
|
|
72
72
|
shortCircuit: true,
|
|
73
|
-
}
|
|
73
|
+
};
|
|
74
74
|
} catch (error) {
|
|
75
|
-
console.error(`Error transforming ${filePath}:`, error)
|
|
76
|
-
throw error
|
|
75
|
+
console.error(`Error transforming ${filePath}:`, error);
|
|
76
|
+
throw error;
|
|
77
77
|
}
|
|
78
78
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { TypicalTransformer } from
|
|
2
|
-
export type { TransformResult } from
|
|
3
|
-
export { loadConfig, validateConfig, defaultConfig } from
|
|
4
|
-
export type { TypicalConfig, TypicalSourceMapConfig } from
|
|
5
|
-
export { BuildTimer, buildTimer } from
|
|
1
|
+
export { TypicalTransformer } from "./transformer.js";
|
|
2
|
+
export type { TransformResult } from "./transformer.js";
|
|
3
|
+
export { loadConfig, validateConfig, defaultConfig } from "./config.js";
|
|
4
|
+
export type { TypicalConfig, TypicalSourceMapConfig } from "./config.js";
|
|
5
|
+
export { BuildTimer, buildTimer } from "./timing.js";
|
package/src/patch-fs.cjs
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
// logs all readFile and readFileSync calls (for debugging)
|
|
2
2
|
|
|
3
|
-
const fs = require(
|
|
4
|
-
const fsp = require(
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const fsp = require("fs/promises");
|
|
5
5
|
|
|
6
6
|
// monkeypatch promises/readFile
|
|
7
|
-
const origFspReadFile = fsp.readFile
|
|
7
|
+
const origFspReadFile = fsp.readFile;
|
|
8
8
|
fsp.readFile = async function (path, ...args) {
|
|
9
|
-
console.log(
|
|
10
|
-
return origFspReadFile.call(this, path, ...args)
|
|
11
|
-
}
|
|
9
|
+
console.log("fsp.readFile", path);
|
|
10
|
+
return origFspReadFile.call(this, path, ...args);
|
|
11
|
+
};
|
|
12
12
|
|
|
13
13
|
// monkeypatch readFile
|
|
14
|
-
const origFsReadFile = fs.readFile
|
|
14
|
+
const origFsReadFile = fs.readFile;
|
|
15
15
|
fs.readFile = async function (path, ...args) {
|
|
16
|
-
console.log(
|
|
17
|
-
return origFsReadFile.call(this, path, ...args)
|
|
18
|
-
}
|
|
16
|
+
console.log("fs.readFile", path);
|
|
17
|
+
return origFsReadFile.call(this, path, ...args);
|
|
18
|
+
};
|
|
19
19
|
|
|
20
20
|
// monkeypatch readFileSync
|
|
21
|
-
const origFsReadFileSync = fs.readFileSync
|
|
21
|
+
const origFsReadFileSync = fs.readFileSync;
|
|
22
22
|
fs.readFileSync = function (path, ...args) {
|
|
23
|
-
console.log(
|
|
24
|
-
return origFsReadFileSync.call(this, path, ...args)
|
|
25
|
-
}
|
|
23
|
+
console.log("fs.readFileSync", path);
|
|
24
|
+
return origFsReadFileSync.call(this, path, ...args);
|
|
25
|
+
};
|
package/src/timing.ts
CHANGED
|
@@ -1,74 +1,60 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Simple build timing utility for debugging performance.
|
|
3
3
|
*/
|
|
4
|
+
|
|
4
5
|
export class BuildTimer {
|
|
5
|
-
private timings
|
|
6
|
-
private starts = new Map<string, number>()
|
|
6
|
+
private timings: Map<string, { start: number; total: number; count: number }> = new Map();
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Reset all timing data.
|
|
10
|
+
*/
|
|
11
|
+
reset(): void {
|
|
12
|
+
this.timings.clear();
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Start timing a named section.
|
|
17
|
+
*/
|
|
18
|
+
start(name: string): void {
|
|
19
|
+
const existing = this.timings.get(name);
|
|
20
|
+
if (existing) {
|
|
21
|
+
existing.start = performance.now();
|
|
22
|
+
} else {
|
|
23
|
+
this.timings.set(name, { start: performance.now(), total: 0, count: 0 });
|
|
20
24
|
}
|
|
21
25
|
}
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
/**
|
|
28
|
+
* End timing a named section.
|
|
29
|
+
*/
|
|
30
|
+
end(name: string): void {
|
|
31
|
+
const timing = this.timings.get(name);
|
|
32
|
+
if (timing && timing.start > 0) {
|
|
33
|
+
timing.total += performance.now() - timing.start;
|
|
34
|
+
timing.count++;
|
|
35
|
+
timing.start = 0;
|
|
36
|
+
}
|
|
26
37
|
}
|
|
27
38
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
let totalTime = 0
|
|
36
|
-
for (const [stage, times] of sortedStages) {
|
|
37
|
-
const total = times.reduce((a, b) => a + b, 0)
|
|
38
|
-
const avg = total / times.length
|
|
39
|
-
const min = Math.min(...times)
|
|
40
|
-
const max = Math.max(...times)
|
|
41
|
-
const count = times.length
|
|
42
|
-
totalTime += total
|
|
43
|
-
|
|
44
|
-
console.log(`${stage}:`)
|
|
45
|
-
console.log(` Count: ${count}`)
|
|
46
|
-
console.log(` Total: ${total.toFixed(2)}ms`)
|
|
47
|
-
console.log(` Avg: ${avg.toFixed(2)}ms`)
|
|
48
|
-
console.log(` Min: ${min.toFixed(2)}ms`)
|
|
49
|
-
console.log(` Max: ${max.toFixed(2)}ms`)
|
|
39
|
+
/**
|
|
40
|
+
* Print a timing report to console.
|
|
41
|
+
*/
|
|
42
|
+
report(prefix: string = "[typical]"): void {
|
|
43
|
+
if (this.timings.size === 0) {
|
|
44
|
+
return;
|
|
50
45
|
}
|
|
51
46
|
|
|
52
|
-
console.log(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const result = new Map()
|
|
59
|
-
for (const [stage, times] of this.timings) {
|
|
60
|
-
const total = times.reduce((a, b) => a + b, 0)
|
|
61
|
-
result.set(stage, {
|
|
62
|
-
count: times.length,
|
|
63
|
-
total,
|
|
64
|
-
avg: total / times.length,
|
|
65
|
-
min: Math.min(...times),
|
|
66
|
-
max: Math.max(...times),
|
|
67
|
-
})
|
|
47
|
+
console.log(`${prefix} Timing report:`);
|
|
48
|
+
for (const [name, timing] of this.timings) {
|
|
49
|
+
const avg = timing.count > 0 ? timing.total / timing.count : 0;
|
|
50
|
+
console.log(
|
|
51
|
+
` ${name}: ${timing.total.toFixed(2)}ms total, ${timing.count} calls, ${avg.toFixed(2)}ms avg`,
|
|
52
|
+
);
|
|
68
53
|
}
|
|
69
|
-
return result
|
|
70
54
|
}
|
|
71
55
|
}
|
|
72
56
|
|
|
73
|
-
|
|
74
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Shared build timer instance.
|
|
59
|
+
*/
|
|
60
|
+
export const buildTimer = new BuildTimer();
|