@ttsc/unplugin 0.8.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 +286 -0
- package/lib/api.d.ts +1 -0
- package/lib/api.js +18 -0
- package/lib/api.js.map +1 -0
- package/lib/bun.d.ts +15 -0
- package/lib/bun.js +34 -0
- package/lib/bun.js.map +1 -0
- package/lib/core/index.d.ts +8 -0
- package/lib/core/index.js +44 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/options.d.ts +32 -0
- package/lib/core/options.js +16 -0
- package/lib/core/options.js.map +1 -0
- package/lib/core/transform.d.ts +11 -0
- package/lib/core/transform.js +307 -0
- package/lib/core/transform.js.map +1 -0
- package/lib/esbuild.d.ts +3 -0
- package/lib/esbuild.js +9 -0
- package/lib/esbuild.js.map +1 -0
- package/lib/farm.d.ts +3 -0
- package/lib/farm.js +9 -0
- package/lib/farm.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/lib/next.d.ts +8 -0
- package/lib/next.js +21 -0
- package/lib/next.js.map +1 -0
- package/lib/rolldown.d.ts +3 -0
- package/lib/rolldown.js +9 -0
- package/lib/rolldown.js.map +1 -0
- package/lib/rollup.d.ts +3 -0
- package/lib/rollup.js +9 -0
- package/lib/rollup.js.map +1 -0
- package/lib/rspack.d.ts +3 -0
- package/lib/rspack.js +9 -0
- package/lib/rspack.js.map +1 -0
- package/lib/vite.d.ts +3 -0
- package/lib/vite.js +9 -0
- package/lib/vite.js.map +1 -0
- package/lib/webpack.d.ts +3 -0
- package/lib/webpack.js +9 -0
- package/lib/webpack.js.map +1 -0
- package/package.json +106 -0
- package/src/api.ts +1 -0
- package/src/bun.ts +47 -0
- package/src/core/index.ts +61 -0
- package/src/core/options.ts +52 -0
- package/src/core/transform.ts +357 -0
- package/src/esbuild.ts +5 -0
- package/src/farm.ts +5 -0
- package/src/index.ts +5 -0
- package/src/next.ts +27 -0
- package/src/rolldown.ts +5 -0
- package/src/rollup.ts +5 -0
- package/src/rspack.ts +5 -0
- package/src/vite.ts +5 -0
- package/src/webpack.ts +5 -0
package/src/bun.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import type { UnpluginContextMeta } from "unplugin";
|
|
3
|
+
|
|
4
|
+
import { unplugin } from "./api";
|
|
5
|
+
import type { TtscUnpluginOptions } from "./core/options";
|
|
6
|
+
|
|
7
|
+
export interface BunLikePlugin {
|
|
8
|
+
name: string;
|
|
9
|
+
setup(build: BunLikeBuild): void | Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface BunLikeBuild {
|
|
13
|
+
onLoad(
|
|
14
|
+
options: { filter: RegExp },
|
|
15
|
+
loader: (args: { path: string }) => Promise<{ contents: string }>,
|
|
16
|
+
): void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const sourceFilePattern = /\.[cm]?[jt]sx?$/;
|
|
20
|
+
|
|
21
|
+
export default function bun(options?: TtscUnpluginOptions): BunLikePlugin {
|
|
22
|
+
return {
|
|
23
|
+
name: "ttsc-unplugin",
|
|
24
|
+
setup(build) {
|
|
25
|
+
const raw = unplugin.raw(options, {} as UnpluginContextMeta);
|
|
26
|
+
build.onLoad({ filter: sourceFilePattern }, async (args) => {
|
|
27
|
+
const source = await fs.readFile(args.path, "utf8");
|
|
28
|
+
const result =
|
|
29
|
+
typeof raw.transform === "function"
|
|
30
|
+
? await raw.transform.call({} as never, source, args.path)
|
|
31
|
+
: undefined;
|
|
32
|
+
if (typeof result === "string") {
|
|
33
|
+
return { contents: result };
|
|
34
|
+
}
|
|
35
|
+
if (
|
|
36
|
+
typeof result === "object" &&
|
|
37
|
+
result !== null &&
|
|
38
|
+
"code" in result &&
|
|
39
|
+
typeof result.code === "string"
|
|
40
|
+
) {
|
|
41
|
+
return { contents: result.code };
|
|
42
|
+
}
|
|
43
|
+
return { contents: source };
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { UnpluginFactory, UnpluginInstance } from "unplugin";
|
|
2
|
+
import { createUnplugin } from "unplugin";
|
|
3
|
+
|
|
4
|
+
import type { TtscUnpluginOptions } from "./options";
|
|
5
|
+
import { resolveOptions } from "./options";
|
|
6
|
+
import { isDeclarationFile, stripQuery, transformTtsc } from "./transform";
|
|
7
|
+
|
|
8
|
+
const name = "ttsc-unplugin";
|
|
9
|
+
const sourceFilePattern = /\.[cm]?[jt]sx?$/;
|
|
10
|
+
const nodeModulesPattern = /(?:^|[/\\])node_modules(?:[/\\]|$)/;
|
|
11
|
+
|
|
12
|
+
const unpluginFactory: UnpluginFactory<
|
|
13
|
+
TtscUnpluginOptions | undefined,
|
|
14
|
+
false
|
|
15
|
+
> = (rawOptions = {}) => {
|
|
16
|
+
const options = resolveOptions(rawOptions);
|
|
17
|
+
let aliases: unknown;
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
name,
|
|
21
|
+
enforce: "pre",
|
|
22
|
+
|
|
23
|
+
vite: {
|
|
24
|
+
configResolved(config) {
|
|
25
|
+
aliases = config.resolve.alias;
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
transformInclude(id) {
|
|
30
|
+
const file = stripQuery(id);
|
|
31
|
+
return isTransformTarget(file);
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
async transform(source, id) {
|
|
35
|
+
const file = stripQuery(id);
|
|
36
|
+
if (!isTransformTarget(file)) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
return transformTtsc(file, source, options, aliases);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const unplugin: UnpluginInstance<TtscUnpluginOptions | undefined, false> =
|
|
45
|
+
createUnplugin(unpluginFactory);
|
|
46
|
+
|
|
47
|
+
export type {
|
|
48
|
+
TtscUnpluginCompilerOptionsJson,
|
|
49
|
+
TtscUnpluginOptions,
|
|
50
|
+
} from "./options";
|
|
51
|
+
export { resolveOptions, transformTtsc, unplugin };
|
|
52
|
+
|
|
53
|
+
export default unplugin;
|
|
54
|
+
|
|
55
|
+
function isTransformTarget(id: string): boolean {
|
|
56
|
+
return (
|
|
57
|
+
sourceFilePattern.test(id) &&
|
|
58
|
+
!isDeclarationFile(id) &&
|
|
59
|
+
!nodeModulesPattern.test(id)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ITtscProjectPluginConfig } from "ttsc";
|
|
2
|
+
|
|
3
|
+
export type TtscUnpluginCompilerOptionsJson = Record<string, unknown>;
|
|
4
|
+
|
|
5
|
+
export interface TtscUnpluginOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Project config used by the bundler adapter.
|
|
8
|
+
*
|
|
9
|
+
* Relative paths resolve from `process.cwd()`. When omitted, the nearest
|
|
10
|
+
* `tsconfig.json` is discovered from the transformed file.
|
|
11
|
+
*/
|
|
12
|
+
project?: string;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Compiler options overlaid on top of the selected project config.
|
|
16
|
+
*
|
|
17
|
+
* This can include `plugins`; `plugins` passed at the top level still wins as
|
|
18
|
+
* the explicit plugin override.
|
|
19
|
+
*/
|
|
20
|
+
compilerOptions?: TtscUnpluginCompilerOptionsJson;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* `ttsc` plugin entries.
|
|
24
|
+
*
|
|
25
|
+
* `undefined` reads `compilerOptions.plugins` from the project config,
|
|
26
|
+
* `false` disables project plugins, and an array overrides the project
|
|
27
|
+
* plugin list.
|
|
28
|
+
*/
|
|
29
|
+
plugins?: readonly ITtscProjectPluginConfig[] | false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ResolvedTtscUnpluginOptions {
|
|
33
|
+
compilerOptions: TtscUnpluginCompilerOptionsJson;
|
|
34
|
+
plugins?: readonly ITtscProjectPluginConfig[] | false;
|
|
35
|
+
project?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const defaultOptions: ResolvedTtscUnpluginOptions = {
|
|
39
|
+
compilerOptions: {},
|
|
40
|
+
plugins: undefined,
|
|
41
|
+
project: undefined,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export function resolveOptions(
|
|
45
|
+
options: TtscUnpluginOptions = {},
|
|
46
|
+
): ResolvedTtscUnpluginOptions {
|
|
47
|
+
return {
|
|
48
|
+
compilerOptions: { ...(options.compilerOptions ?? {}) },
|
|
49
|
+
plugins: "plugins" in options ? options.plugins : defaultOptions.plugins,
|
|
50
|
+
project: options.project ?? defaultOptions.project,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import * as Diff from "diff-match-patch-es";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import MagicString from "magic-string";
|
|
5
|
+
import type {
|
|
6
|
+
ITtscCompilerDiagnostic,
|
|
7
|
+
ITtscCompilerTransformation,
|
|
8
|
+
} from "ttsc";
|
|
9
|
+
import { TtscCompiler } from "ttsc";
|
|
10
|
+
import type { TransformResult } from "unplugin";
|
|
11
|
+
|
|
12
|
+
import type { ResolvedTtscUnpluginOptions } from "./options";
|
|
13
|
+
|
|
14
|
+
export type TtscTransformResult = Exclude<
|
|
15
|
+
TransformResult,
|
|
16
|
+
string | null | undefined
|
|
17
|
+
>;
|
|
18
|
+
|
|
19
|
+
export interface TtscTransformAlias {
|
|
20
|
+
find: string | RegExp;
|
|
21
|
+
replacement: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function transformTtsc(
|
|
25
|
+
id: string,
|
|
26
|
+
source: string,
|
|
27
|
+
options: ResolvedTtscUnpluginOptions,
|
|
28
|
+
aliases?: unknown,
|
|
29
|
+
): Promise<TtscTransformResult | undefined> {
|
|
30
|
+
const file = path.resolve(stripQuery(id));
|
|
31
|
+
if (isDeclarationFile(file)) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const tsconfig = resolveTsconfig(file, options.project);
|
|
36
|
+
const tsconfigDir = path.dirname(tsconfig);
|
|
37
|
+
const baseUrl = resolveBaseUrl(tsconfigDir, options.compilerOptions);
|
|
38
|
+
const aliasPaths = createAliasPaths(baseUrl, aliases);
|
|
39
|
+
const configured = createTransformTsconfig({
|
|
40
|
+
aliasPaths,
|
|
41
|
+
baseUrl,
|
|
42
|
+
compilerOptions: options.compilerOptions,
|
|
43
|
+
tsconfig,
|
|
44
|
+
});
|
|
45
|
+
try {
|
|
46
|
+
const effectiveTsconfig = configured.path;
|
|
47
|
+
const result = new TtscCompiler({
|
|
48
|
+
cwd: path.dirname(effectiveTsconfig),
|
|
49
|
+
plugins: options.plugins,
|
|
50
|
+
tsconfig: effectiveTsconfig,
|
|
51
|
+
}).transform();
|
|
52
|
+
const code = selectTransformedSource({
|
|
53
|
+
file,
|
|
54
|
+
projectRoot: path.dirname(effectiveTsconfig),
|
|
55
|
+
result,
|
|
56
|
+
});
|
|
57
|
+
return createTransformResult(source, code, file);
|
|
58
|
+
} finally {
|
|
59
|
+
configured.dispose();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function stripQuery(id: string): string {
|
|
64
|
+
const query = id.search(/[?#]/);
|
|
65
|
+
const clean = query === -1 ? id : id.slice(0, query);
|
|
66
|
+
return clean.endsWith("?__rslib_entry__")
|
|
67
|
+
? clean.slice(0, -"?__rslib_entry__".length)
|
|
68
|
+
: clean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function isDeclarationFile(id: string): boolean {
|
|
72
|
+
return id.endsWith(".d.ts") || id.endsWith(".d.mts") || id.endsWith(".d.cts");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function createTransformResult(
|
|
76
|
+
source: string,
|
|
77
|
+
code: string,
|
|
78
|
+
id: string,
|
|
79
|
+
): TtscTransformResult | undefined {
|
|
80
|
+
if (source === code) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const magic = new MagicString(source);
|
|
85
|
+
const diff = Diff.diff(source, code);
|
|
86
|
+
Diff.diffCleanupSemantic(diff);
|
|
87
|
+
|
|
88
|
+
let offset = 0;
|
|
89
|
+
for (let index = 0; index < diff.length; index += 1) {
|
|
90
|
+
const [type, text] = diff[index]!;
|
|
91
|
+
if (type === 0) {
|
|
92
|
+
offset += text.length;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (type === 1) {
|
|
96
|
+
magic.prependLeft(offset, text);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const next = diff[index + 1];
|
|
101
|
+
if (next?.[0] === 1) {
|
|
102
|
+
magic.update(offset, offset + text.length, next[1]);
|
|
103
|
+
index += 1;
|
|
104
|
+
} else {
|
|
105
|
+
magic.remove(offset, offset + text.length);
|
|
106
|
+
}
|
|
107
|
+
offset += text.length;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!magic.hasChanged()) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
code: magic.toString(),
|
|
115
|
+
map: magic.generateMap({
|
|
116
|
+
file: `${id}.map`,
|
|
117
|
+
includeContent: true,
|
|
118
|
+
source: id,
|
|
119
|
+
}),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function createTransformTsconfig(props: {
|
|
124
|
+
aliasPaths: Record<string, string[]>;
|
|
125
|
+
baseUrl: string;
|
|
126
|
+
compilerOptions: Record<string, unknown>;
|
|
127
|
+
tsconfig: string;
|
|
128
|
+
}): { path: string; dispose: () => void } {
|
|
129
|
+
const compilerOptions = {
|
|
130
|
+
...props.compilerOptions,
|
|
131
|
+
...createAliasCompilerOptions(props),
|
|
132
|
+
};
|
|
133
|
+
if (Object.keys(compilerOptions).length === 0) {
|
|
134
|
+
return {
|
|
135
|
+
path: props.tsconfig,
|
|
136
|
+
dispose: () => undefined,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const directory = path.dirname(props.tsconfig);
|
|
141
|
+
const file = path.join(
|
|
142
|
+
directory,
|
|
143
|
+
`.ttsc-unplugin-${process.pid}-${Date.now()}-${Math.random()
|
|
144
|
+
.toString(36)
|
|
145
|
+
.slice(2)}.json`,
|
|
146
|
+
);
|
|
147
|
+
fs.writeFileSync(
|
|
148
|
+
file,
|
|
149
|
+
JSON.stringify(
|
|
150
|
+
{
|
|
151
|
+
extends: `./${path.basename(props.tsconfig)}`,
|
|
152
|
+
compilerOptions,
|
|
153
|
+
},
|
|
154
|
+
null,
|
|
155
|
+
2,
|
|
156
|
+
),
|
|
157
|
+
"utf8",
|
|
158
|
+
);
|
|
159
|
+
return {
|
|
160
|
+
path: file,
|
|
161
|
+
dispose: () => fs.rmSync(file, { force: true }),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function createAliasCompilerOptions(props: {
|
|
166
|
+
aliasPaths: Record<string, string[]>;
|
|
167
|
+
baseUrl: string;
|
|
168
|
+
compilerOptions: Record<string, unknown>;
|
|
169
|
+
}): Record<string, unknown> {
|
|
170
|
+
if (Object.keys(props.aliasPaths).length === 0) {
|
|
171
|
+
return {};
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
baseUrl: toCompilerPath(props.baseUrl, props.compilerOptions),
|
|
175
|
+
paths: {
|
|
176
|
+
...readPaths(props.compilerOptions.paths),
|
|
177
|
+
...props.aliasPaths,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function readPaths(value: unknown): Record<string, string[]> {
|
|
183
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
184
|
+
return {};
|
|
185
|
+
}
|
|
186
|
+
const output: Record<string, string[]> = {};
|
|
187
|
+
for (const [key, paths] of Object.entries(value)) {
|
|
188
|
+
if (!Array.isArray(paths)) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const filtered = paths.filter(
|
|
192
|
+
(entry): entry is string => typeof entry === "string",
|
|
193
|
+
);
|
|
194
|
+
if (filtered.length !== 0) {
|
|
195
|
+
output[key] = filtered;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return output;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function resolveBaseUrl(
|
|
202
|
+
tsconfigDir: string,
|
|
203
|
+
compilerOptions: Record<string, unknown>,
|
|
204
|
+
): string {
|
|
205
|
+
return typeof compilerOptions.baseUrl === "string"
|
|
206
|
+
? path.resolve(tsconfigDir, compilerOptions.baseUrl)
|
|
207
|
+
: tsconfigDir;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function toCompilerPath(
|
|
211
|
+
absoluteBaseUrl: string,
|
|
212
|
+
compilerOptions: Record<string, unknown>,
|
|
213
|
+
): string {
|
|
214
|
+
return typeof compilerOptions.baseUrl === "string"
|
|
215
|
+
? compilerOptions.baseUrl
|
|
216
|
+
: absoluteBaseUrl;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function createAliasPaths(
|
|
220
|
+
baseUrl: string,
|
|
221
|
+
aliases: unknown,
|
|
222
|
+
): Record<string, string[]> {
|
|
223
|
+
const paths: Record<string, string[]> = {};
|
|
224
|
+
for (const alias of normalizeAliases(aliases)) {
|
|
225
|
+
if (typeof alias.find !== "string" || alias.find.length === 0) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (alias.find.includes("*")) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
const key = alias.find.replace(/\/+$/, "");
|
|
232
|
+
if (key.length === 0) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const replacement = path.isAbsolute(alias.replacement)
|
|
236
|
+
? alias.replacement
|
|
237
|
+
: path.resolve(process.cwd(), alias.replacement);
|
|
238
|
+
const target = normalizePath(path.relative(baseUrl, replacement) || ".");
|
|
239
|
+
paths[key] = [target];
|
|
240
|
+
paths[`${key}/*`] = [`${target}/*`];
|
|
241
|
+
}
|
|
242
|
+
return paths;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function normalizeAliases(aliases: unknown): TtscTransformAlias[] {
|
|
246
|
+
if (Array.isArray(aliases)) {
|
|
247
|
+
return aliases.filter(isAlias);
|
|
248
|
+
}
|
|
249
|
+
if (typeof aliases === "object" && aliases !== null) {
|
|
250
|
+
return Object.entries(aliases)
|
|
251
|
+
.filter(
|
|
252
|
+
(entry): entry is [string, string] => typeof entry[1] === "string",
|
|
253
|
+
)
|
|
254
|
+
.map(([find, replacement]) => ({ find, replacement }));
|
|
255
|
+
}
|
|
256
|
+
return [];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function isAlias(value: unknown): value is TtscTransformAlias {
|
|
260
|
+
return (
|
|
261
|
+
typeof value === "object" &&
|
|
262
|
+
value !== null &&
|
|
263
|
+
"find" in value &&
|
|
264
|
+
"replacement" in value &&
|
|
265
|
+
(typeof value.find === "string" || value.find instanceof RegExp) &&
|
|
266
|
+
typeof value.replacement === "string"
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function selectTransformedSource(props: {
|
|
271
|
+
file: string;
|
|
272
|
+
projectRoot: string;
|
|
273
|
+
result: ITtscCompilerTransformation;
|
|
274
|
+
}): string {
|
|
275
|
+
if (props.result.type === "exception") {
|
|
276
|
+
throw new Error(formatUnknownError(props.result.error));
|
|
277
|
+
}
|
|
278
|
+
if (props.result.type === "failure") {
|
|
279
|
+
throw new Error(formatDiagnostics(props.result.diagnostics));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const key = toProjectKey(props.projectRoot, props.file);
|
|
283
|
+
const direct = props.result.typescript[key];
|
|
284
|
+
if (direct !== undefined) {
|
|
285
|
+
return direct;
|
|
286
|
+
}
|
|
287
|
+
for (const [candidate, source] of Object.entries(props.result.typescript)) {
|
|
288
|
+
if (path.resolve(props.projectRoot, candidate) === props.file) {
|
|
289
|
+
return source;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
throw new Error(`ttsc transform did not return output for ${props.file}`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function formatDiagnostics(diagnostics: ITtscCompilerDiagnostic[]): string {
|
|
296
|
+
if (diagnostics.length === 0) {
|
|
297
|
+
return "ttsc transform failed";
|
|
298
|
+
}
|
|
299
|
+
return diagnostics
|
|
300
|
+
.map((diag) =>
|
|
301
|
+
[
|
|
302
|
+
diag.file ?? "ttsc",
|
|
303
|
+
diag.line === undefined
|
|
304
|
+
? undefined
|
|
305
|
+
: `${diag.line}:${diag.character ?? 1}`,
|
|
306
|
+
diag.messageText,
|
|
307
|
+
]
|
|
308
|
+
.filter((part) => part !== undefined && part !== "")
|
|
309
|
+
.join(": "),
|
|
310
|
+
)
|
|
311
|
+
.join("\n");
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function formatUnknownError(error: unknown): string {
|
|
315
|
+
if (error instanceof Error) {
|
|
316
|
+
return error.message;
|
|
317
|
+
}
|
|
318
|
+
if (
|
|
319
|
+
typeof error === "object" &&
|
|
320
|
+
error !== null &&
|
|
321
|
+
"message" in error &&
|
|
322
|
+
typeof error.message === "string"
|
|
323
|
+
) {
|
|
324
|
+
return error.message;
|
|
325
|
+
}
|
|
326
|
+
return String(error);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function resolveTsconfig(file: string, tsconfig?: string): string {
|
|
330
|
+
if (tsconfig !== undefined) {
|
|
331
|
+
return path.isAbsolute(tsconfig)
|
|
332
|
+
? tsconfig
|
|
333
|
+
: path.resolve(process.cwd(), tsconfig);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
let current = path.dirname(file);
|
|
337
|
+
while (true) {
|
|
338
|
+
const candidate = path.join(current, "tsconfig.json");
|
|
339
|
+
if (fs.existsSync(candidate)) {
|
|
340
|
+
return candidate;
|
|
341
|
+
}
|
|
342
|
+
const parent = path.dirname(current);
|
|
343
|
+
if (parent === current) {
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
current = parent;
|
|
347
|
+
}
|
|
348
|
+
return path.resolve(process.cwd(), "tsconfig.json");
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function toProjectKey(root: string, file: string): string {
|
|
352
|
+
return normalizePath(path.relative(root, file));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function normalizePath(file: string): string {
|
|
356
|
+
return file.replace(/\\/g, "/");
|
|
357
|
+
}
|
package/src/esbuild.ts
ADDED
package/src/farm.ts
ADDED
package/src/index.ts
ADDED
package/src/next.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { TtscUnpluginOptions } from "./core/options";
|
|
2
|
+
import webpack from "./webpack";
|
|
3
|
+
|
|
4
|
+
export type NextLikeConfig = Record<string, unknown> & {
|
|
5
|
+
webpack?: (config: WebpackLikeConfig, options: unknown) => WebpackLikeConfig;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type WebpackLikeConfig = Record<string, unknown> & {
|
|
9
|
+
plugins?: unknown[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default function next(
|
|
13
|
+
nextConfig: NextLikeConfig = {},
|
|
14
|
+
options?: TtscUnpluginOptions,
|
|
15
|
+
): NextLikeConfig {
|
|
16
|
+
return {
|
|
17
|
+
...nextConfig,
|
|
18
|
+
webpack(config: WebpackLikeConfig, webpackOptions: unknown) {
|
|
19
|
+
config.plugins = Array.isArray(config.plugins) ? config.plugins : [];
|
|
20
|
+
config.plugins.unshift(webpack(options));
|
|
21
|
+
if (typeof nextConfig.webpack === "function") {
|
|
22
|
+
return nextConfig.webpack(config, webpackOptions);
|
|
23
|
+
}
|
|
24
|
+
return config;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
package/src/rolldown.ts
ADDED
package/src/rollup.ts
ADDED
package/src/rspack.ts
ADDED
package/src/vite.ts
ADDED