@kithinji/pod 1.0.20 → 1.0.22
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 +439 -0
- package/dist/main.js +109 -2
- package/dist/main.js.map +2 -2
- package/dist/types/docker/docker.d.ts.map +1 -1
- package/package.json +31 -8
- package/build.js +0 -22
- package/src/add/component/component.ts +0 -496
- package/src/add/component/index.ts +0 -1
- package/src/add/index.ts +0 -3
- package/src/add/module/index.ts +0 -1
- package/src/add/module/module.ts +0 -545
- package/src/add/new/index.ts +0 -198
- package/src/config/config.ts +0 -141
- package/src/config/index.ts +0 -1
- package/src/deploy/deploy.ts +0 -592
- package/src/deploy/index.ts +0 -1
- package/src/dev/index.ts +0 -1
- package/src/dev/project.ts +0 -45
- package/src/dev/server.ts +0 -191
- package/src/docker/docker.ts +0 -592
- package/src/docker/index.ts +0 -1
- package/src/macros/expand_macros.ts +0 -791
- package/src/macros/index.ts +0 -2
- package/src/macros/macro_executer.ts +0 -189
- package/src/main.ts +0 -106
- package/src/plugins/analyzers/graph.ts +0 -279
- package/src/plugins/css/index.ts +0 -25
- package/src/plugins/generators/generate_controller.ts +0 -308
- package/src/plugins/generators/generate_rsc.ts +0 -274
- package/src/plugins/generators/generate_server_component.ts +0 -455
- package/src/plugins/generators/tsx_server_stub.ts +0 -315
- package/src/plugins/index.ts +0 -3
- package/src/plugins/my.ts +0 -282
- package/src/plugins/transformers/j2d.ts +0 -1080
- package/src/store/index.ts +0 -1
- package/src/store/store.ts +0 -44
- package/src/utils/cases.ts +0 -15
- package/src/utils/create.ts +0 -26
- package/src/utils/index.ts +0 -2
- package/tsconfig.json +0 -27
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
import * as path from "path";
|
|
2
|
-
import { createHash } from "crypto";
|
|
3
|
-
import { parseSync, printSync } from "@swc/core";
|
|
4
|
-
import type {
|
|
5
|
-
ModuleItem,
|
|
6
|
-
ClassDeclaration,
|
|
7
|
-
Decorator,
|
|
8
|
-
ImportDeclaration,
|
|
9
|
-
} from "@swc/core";
|
|
10
|
-
|
|
11
|
-
interface ClassStub {
|
|
12
|
-
name: string;
|
|
13
|
-
propsType: string;
|
|
14
|
-
decorators: string[];
|
|
15
|
-
constructorParams: string[];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface ImportMap {
|
|
19
|
-
[localName: string]: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function generateServerStub(filePath: string, code: string): string {
|
|
23
|
-
const hash = createHash("md5").update(filePath).digest("hex").slice(0, 8);
|
|
24
|
-
const relativeFromSrc = filePath.split("/src/")[1];
|
|
25
|
-
const parsed = path.parse(relativeFromSrc);
|
|
26
|
-
|
|
27
|
-
const fileName = path.join("src", parsed.dir, parsed.name);
|
|
28
|
-
|
|
29
|
-
const ast = parseSync(code, {
|
|
30
|
-
syntax: "typescript",
|
|
31
|
-
tsx: filePath.endsWith("x"),
|
|
32
|
-
decorators: true,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const importMap: ImportMap = {};
|
|
36
|
-
for (const item of ast.body) {
|
|
37
|
-
if (item.type === "ImportDeclaration") {
|
|
38
|
-
const decl = item as ImportDeclaration;
|
|
39
|
-
for (const specifier of decl.specifiers ?? []) {
|
|
40
|
-
let localName: string;
|
|
41
|
-
if (specifier.type === "ImportSpecifier") {
|
|
42
|
-
localName = specifier.local.value;
|
|
43
|
-
} else if (specifier.type === "ImportDefaultSpecifier") {
|
|
44
|
-
localName = specifier.local.value;
|
|
45
|
-
} else {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
importMap[localName] = decl.source.value;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const preservedNodes: ModuleItem[] = [];
|
|
54
|
-
const stubbedClasses: ClassStub[] = [];
|
|
55
|
-
|
|
56
|
-
for (const item of ast.body) {
|
|
57
|
-
let shouldStub = false;
|
|
58
|
-
|
|
59
|
-
if (
|
|
60
|
-
item.type === "ExportDeclaration" &&
|
|
61
|
-
item.declaration?.type === "ClassDeclaration"
|
|
62
|
-
) {
|
|
63
|
-
const classDecl = item.declaration as ClassDeclaration;
|
|
64
|
-
|
|
65
|
-
if (hasComponentDecorator(classDecl.decorators)) {
|
|
66
|
-
shouldStub = true;
|
|
67
|
-
const stub = extractClassStub(classDecl);
|
|
68
|
-
if (stub) {
|
|
69
|
-
stubbedClasses.push(stub);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (!shouldStub) {
|
|
75
|
-
preservedNodes.push(item);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const preservedCode =
|
|
80
|
-
preservedNodes.length > 0
|
|
81
|
-
? printSync({
|
|
82
|
-
type: "Module",
|
|
83
|
-
span: ast.span,
|
|
84
|
-
body: preservedNodes,
|
|
85
|
-
interpreter: ast.interpreter,
|
|
86
|
-
}).code
|
|
87
|
-
: "";
|
|
88
|
-
|
|
89
|
-
const stubCode = stubbedClasses
|
|
90
|
-
.map((stub) => generateClassCode(stub, hash, fileName))
|
|
91
|
-
.join("\n\n");
|
|
92
|
-
|
|
93
|
-
return `
|
|
94
|
-
${preservedCode}
|
|
95
|
-
${stubCode}
|
|
96
|
-
`.trim();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function hasComponentDecorator(decorators?: Decorator[]): boolean {
|
|
100
|
-
if (!decorators) return false;
|
|
101
|
-
return decorators.some((decorator) => {
|
|
102
|
-
const expr = decorator.expression;
|
|
103
|
-
if (expr.type === "Identifier" && expr.value === "Component") {
|
|
104
|
-
return true;
|
|
105
|
-
}
|
|
106
|
-
if (
|
|
107
|
-
expr.type === "CallExpression" &&
|
|
108
|
-
expr.callee.type === "Identifier" &&
|
|
109
|
-
expr.callee.value === "Component"
|
|
110
|
-
) {
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
return false;
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function extractClassStub(classDecl: ClassDeclaration): ClassStub | null {
|
|
118
|
-
const className = classDecl.identifier?.value;
|
|
119
|
-
if (!className) return null;
|
|
120
|
-
|
|
121
|
-
let propsType = "{}";
|
|
122
|
-
const decorators: string[] = [];
|
|
123
|
-
const constructorParams: string[] = [];
|
|
124
|
-
|
|
125
|
-
if (classDecl.decorators) {
|
|
126
|
-
for (const dec of classDecl.decorators) {
|
|
127
|
-
const str = stringifyDecorator(dec);
|
|
128
|
-
if (str) decorators.push(str);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
for (const member of classDecl.body) {
|
|
133
|
-
if (member.type === "ClassProperty") {
|
|
134
|
-
if (member.key.type === "Identifier" && member.key.value === "props") {
|
|
135
|
-
propsType = extractPropsType(member);
|
|
136
|
-
}
|
|
137
|
-
} else if (member.type === "Constructor") {
|
|
138
|
-
for (const param of member.params) {
|
|
139
|
-
const paramStr = stringifyParam(param);
|
|
140
|
-
if (paramStr) constructorParams.push(paramStr);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
name: className,
|
|
147
|
-
propsType,
|
|
148
|
-
decorators,
|
|
149
|
-
constructorParams,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export function stringifyDecorator(decorator: Decorator): string {
|
|
154
|
-
const exprCode = printSync({
|
|
155
|
-
type: "Module",
|
|
156
|
-
span: { start: 0, end: 0, ctxt: 0 },
|
|
157
|
-
body: [
|
|
158
|
-
{
|
|
159
|
-
type: "ExpressionStatement",
|
|
160
|
-
expression: decorator.expression,
|
|
161
|
-
span: { start: 0, end: 0, ctxt: 0 },
|
|
162
|
-
},
|
|
163
|
-
],
|
|
164
|
-
interpreter: "",
|
|
165
|
-
}).code;
|
|
166
|
-
|
|
167
|
-
const cleanCode = exprCode.replace(/^#!.*\n/, "").trim();
|
|
168
|
-
|
|
169
|
-
return `@${cleanCode.replace(/;$/, "")}`;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function extractPropsType(member: any): string {
|
|
173
|
-
const typeAnn = member.typeAnnotation?.typeAnnotation;
|
|
174
|
-
if (!typeAnn) return "{}";
|
|
175
|
-
|
|
176
|
-
if (typeAnn.type === "TsTypeLiteral") {
|
|
177
|
-
const props: string[] = [];
|
|
178
|
-
for (const m of typeAnn.members) {
|
|
179
|
-
if (m.type === "TsPropertySignature") {
|
|
180
|
-
const key = m.key.type === "Identifier" ? m.key.value : "?";
|
|
181
|
-
const t = m.typeAnnotation
|
|
182
|
-
? stringifyType(m.typeAnnotation.typeAnnotation)
|
|
183
|
-
: "any";
|
|
184
|
-
props.push(`${key}: ${t}`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return `{ ${props.join("; ")} }`;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return stringifyType(typeAnn);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function stringifyParam(param: any): string {
|
|
194
|
-
let decorators: string[] = [];
|
|
195
|
-
if (param.decorators) {
|
|
196
|
-
for (const d of param.decorators) {
|
|
197
|
-
const str = stringifyDecorator(d);
|
|
198
|
-
if (str) decorators.push(str);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const decoratorPrefix = decorators.length ? decorators.join(" ") + " " : "";
|
|
202
|
-
|
|
203
|
-
let typeName = "any";
|
|
204
|
-
let paramName = "";
|
|
205
|
-
let accessibility = "";
|
|
206
|
-
|
|
207
|
-
if (param.type === "TsParameterProperty") {
|
|
208
|
-
accessibility = param.accessibility || "";
|
|
209
|
-
const inner = param.param;
|
|
210
|
-
if (inner.type !== "Identifier") return "";
|
|
211
|
-
|
|
212
|
-
paramName = inner.value;
|
|
213
|
-
if (inner.typeAnnotation?.typeAnnotation) {
|
|
214
|
-
typeName = extractTypeName(inner.typeAnnotation.typeAnnotation);
|
|
215
|
-
}
|
|
216
|
-
} else if (param.type === "Parameter") {
|
|
217
|
-
const pat = param.pat;
|
|
218
|
-
if (pat.type !== "Identifier") return "";
|
|
219
|
-
|
|
220
|
-
paramName = pat.value;
|
|
221
|
-
if (pat.typeAnnotation?.typeAnnotation) {
|
|
222
|
-
typeName = extractTypeName(pat.typeAnnotation.typeAnnotation);
|
|
223
|
-
}
|
|
224
|
-
} else {
|
|
225
|
-
return "";
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const accessPrefix = accessibility ? `${accessibility} ` : "";
|
|
229
|
-
const result = `${decoratorPrefix}${accessPrefix}${paramName}: ${typeName}`;
|
|
230
|
-
|
|
231
|
-
return result;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function extractTypeName(typeNode: any): string {
|
|
235
|
-
if (
|
|
236
|
-
typeNode.type === "TsTypeReference" &&
|
|
237
|
-
typeNode.typeName.type === "Identifier"
|
|
238
|
-
) {
|
|
239
|
-
return typeNode.typeName.value;
|
|
240
|
-
}
|
|
241
|
-
return stringifyType(typeNode);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function stringifyType(typeNode: any): string {
|
|
245
|
-
if (!typeNode) return "any";
|
|
246
|
-
|
|
247
|
-
switch (typeNode.type) {
|
|
248
|
-
case "TsKeywordType":
|
|
249
|
-
return typeNode.kind;
|
|
250
|
-
case "TsTypeReference":
|
|
251
|
-
if (typeNode.typeName.type === "Identifier")
|
|
252
|
-
return typeNode.typeName.value;
|
|
253
|
-
if (typeNode.typeName.type === "TsQualifiedName") {
|
|
254
|
-
return `${stringifyQualifiedName(typeNode.typeName.left)}.${
|
|
255
|
-
typeNode.typeName.right.value
|
|
256
|
-
}`;
|
|
257
|
-
}
|
|
258
|
-
return "any";
|
|
259
|
-
case "TsArrayType":
|
|
260
|
-
return `${stringifyType(typeNode.elemType)}[]`;
|
|
261
|
-
case "TsUnionType":
|
|
262
|
-
return typeNode.types.map(stringifyType).join(" | ");
|
|
263
|
-
case "TsIntersectionType":
|
|
264
|
-
return typeNode.types.map(stringifyType).join(" & ");
|
|
265
|
-
default:
|
|
266
|
-
return "any";
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function stringifyQualifiedName(node: any): string {
|
|
271
|
-
if (node.type === "Identifier") return node.value;
|
|
272
|
-
if (node.type === "TsQualifiedName") {
|
|
273
|
-
return `${stringifyQualifiedName(node.left)}.${node.right.value}`;
|
|
274
|
-
}
|
|
275
|
-
return "any";
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
function generateClassCode(
|
|
279
|
-
stub: ClassStub,
|
|
280
|
-
hash: string,
|
|
281
|
-
fileName: string
|
|
282
|
-
): string {
|
|
283
|
-
const clientId = `${stub.name}_${hash}`;
|
|
284
|
-
const clientPath = `/${fileName}.js`;
|
|
285
|
-
const decoratorsStr =
|
|
286
|
-
stub.decorators.length > 0 ? stub.decorators.join("\n") + "\n" : "";
|
|
287
|
-
|
|
288
|
-
const constructorStr = stub.constructorParams.length
|
|
289
|
-
? `constructor(${stub.constructorParams.join(", ")}) {}`
|
|
290
|
-
: "constructor() {}";
|
|
291
|
-
|
|
292
|
-
return `
|
|
293
|
-
${decoratorsStr}export class ${stub.name} {
|
|
294
|
-
props!: ${stub.propsType};
|
|
295
|
-
${constructorStr}
|
|
296
|
-
build() {
|
|
297
|
-
const inputProps = { ...this.props };
|
|
298
|
-
return {
|
|
299
|
-
$$typeof: Symbol.for("orca.client.component"),
|
|
300
|
-
id: "${clientId}_" + Math.random().toString(36).slice(2, 9),
|
|
301
|
-
type: "${stub.name}",
|
|
302
|
-
props: {
|
|
303
|
-
...inputProps,
|
|
304
|
-
__clientComponent: {
|
|
305
|
-
id: "${clientId}",
|
|
306
|
-
path: "${clientPath}",
|
|
307
|
-
name: "${stub.name}",
|
|
308
|
-
}
|
|
309
|
-
},
|
|
310
|
-
key: null
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
`.trim();
|
|
315
|
-
}
|
package/src/plugins/index.ts
DELETED
package/src/plugins/my.ts
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
import type { Plugin, OnLoadArgs, OnLoadResult } from "esbuild";
|
|
2
|
-
import * as fs from "fs/promises";
|
|
3
|
-
import { ReactConfig, transform } from "@swc/core";
|
|
4
|
-
import * as babel from "@babel/core";
|
|
5
|
-
import * as path from "path";
|
|
6
|
-
import { expandMacros } from "@/macros";
|
|
7
|
-
import { DependencyGraph, FileNode } from "./analyzers/graph";
|
|
8
|
-
import { generateController } from "./generators/generate_controller";
|
|
9
|
-
import { generateServerStub } from "./generators/tsx_server_stub";
|
|
10
|
-
import { j2d } from "./transformers/j2d";
|
|
11
|
-
import { generateServerComponent } from "./generators/generate_server_component";
|
|
12
|
-
import { generateRscStub } from "./generators/generate_rsc";
|
|
13
|
-
import { Store } from "@/store";
|
|
14
|
-
|
|
15
|
-
interface MyPluginParams {
|
|
16
|
-
isServerBuild: boolean;
|
|
17
|
-
graph?: DependencyGraph;
|
|
18
|
-
onClientFound: (path: string) => void;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
type FileDirective = "interactive" | "public" | null;
|
|
22
|
-
|
|
23
|
-
interface FileMetadata {
|
|
24
|
-
source: string;
|
|
25
|
-
path: string;
|
|
26
|
-
isTsx: boolean;
|
|
27
|
-
directive: FileDirective;
|
|
28
|
-
isPublicFile: boolean;
|
|
29
|
-
isInteractiveFile: boolean;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async function swcTransform(
|
|
33
|
-
source: string,
|
|
34
|
-
pathStr: string,
|
|
35
|
-
tsx: boolean = false,
|
|
36
|
-
react?: ReactConfig
|
|
37
|
-
): Promise<OnLoadResult> {
|
|
38
|
-
const resolveDir = path.dirname(pathStr);
|
|
39
|
-
|
|
40
|
-
const swcResult = await transform(source, {
|
|
41
|
-
filename: pathStr,
|
|
42
|
-
jsc: {
|
|
43
|
-
parser: {
|
|
44
|
-
syntax: "typescript",
|
|
45
|
-
tsx,
|
|
46
|
-
decorators: true,
|
|
47
|
-
},
|
|
48
|
-
transform: {
|
|
49
|
-
legacyDecorator: true,
|
|
50
|
-
decoratorMetadata: true,
|
|
51
|
-
react,
|
|
52
|
-
},
|
|
53
|
-
target: "esnext",
|
|
54
|
-
},
|
|
55
|
-
isModule: true,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
contents: swcResult.code,
|
|
60
|
-
loader: "js",
|
|
61
|
-
resolveDir,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function parseFileMetadata(source: string, path: string): FileMetadata {
|
|
66
|
-
const isTsx = path.endsWith(".tsx");
|
|
67
|
-
const isInteractiveFile =
|
|
68
|
-
source.startsWith('"use interactive"') ||
|
|
69
|
-
source.startsWith("'use interactive'");
|
|
70
|
-
const isPublicFile =
|
|
71
|
-
source.startsWith('"use public"') || source.startsWith("'use public'");
|
|
72
|
-
|
|
73
|
-
let directive: FileDirective = null;
|
|
74
|
-
if (isInteractiveFile) directive = "interactive";
|
|
75
|
-
else if (isPublicFile) directive = "public";
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
source,
|
|
79
|
-
path,
|
|
80
|
-
isTsx,
|
|
81
|
-
directive,
|
|
82
|
-
isPublicFile,
|
|
83
|
-
isInteractiveFile,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
class ServerBuildTransformer {
|
|
88
|
-
async transformPublicFile(
|
|
89
|
-
source: string,
|
|
90
|
-
path: string
|
|
91
|
-
): Promise<OnLoadResult> {
|
|
92
|
-
const controllerCode = generateController(path, source);
|
|
93
|
-
|
|
94
|
-
if (controllerCode) {
|
|
95
|
-
source = `${source}\n\n${controllerCode}\n`;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return swcTransform(source, path);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async transformRegularTypeScript(
|
|
102
|
-
source: string,
|
|
103
|
-
path: string,
|
|
104
|
-
isPublic: boolean
|
|
105
|
-
): Promise<OnLoadResult> {
|
|
106
|
-
if (isPublic) {
|
|
107
|
-
return this.transformPublicFile(source, path);
|
|
108
|
-
}
|
|
109
|
-
return swcTransform(source, path);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async transformServerTsx(
|
|
113
|
-
source: string,
|
|
114
|
-
path: string
|
|
115
|
-
): Promise<OnLoadResult> {
|
|
116
|
-
return swcTransform(source, path, true, {
|
|
117
|
-
runtime: "automatic",
|
|
118
|
-
importSource: "@kithinji/orca",
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async transformInteractiveTsxStub(
|
|
123
|
-
source: string,
|
|
124
|
-
path: string
|
|
125
|
-
): Promise<OnLoadResult> {
|
|
126
|
-
const stubSource = generateServerStub(path, source);
|
|
127
|
-
|
|
128
|
-
return swcTransform(stubSource, path);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async process(
|
|
132
|
-
metadata: FileMetadata,
|
|
133
|
-
onClientFound: (path: string) => void
|
|
134
|
-
): Promise<OnLoadResult> {
|
|
135
|
-
const expandedSource = await expandMacros(metadata.source, metadata.path);
|
|
136
|
-
|
|
137
|
-
const expandedMetadata = { ...metadata, source: expandedSource };
|
|
138
|
-
const { source, path, isTsx, isInteractiveFile, isPublicFile } =
|
|
139
|
-
expandedMetadata;
|
|
140
|
-
|
|
141
|
-
if (isTsx) {
|
|
142
|
-
if (isInteractiveFile) {
|
|
143
|
-
onClientFound(path);
|
|
144
|
-
const clientCode = await this.transformInteractiveTsxStub(source, path);
|
|
145
|
-
|
|
146
|
-
const store = Store.getInstance();
|
|
147
|
-
|
|
148
|
-
store.set(path, clientCode.contents);
|
|
149
|
-
|
|
150
|
-
return clientCode;
|
|
151
|
-
}
|
|
152
|
-
return this.transformServerTsx(source, path);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return this.transformRegularTypeScript(source, path, isPublicFile);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
class ClientBuildTransformer {
|
|
160
|
-
async transformInteractiveTsx(
|
|
161
|
-
source: string,
|
|
162
|
-
path: string
|
|
163
|
-
): Promise<OnLoadResult> {
|
|
164
|
-
const swcResult = await swcTransform(source, path, true, {
|
|
165
|
-
runtime: "preserve",
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
const babelResult = await babel.transformAsync(
|
|
169
|
-
swcResult.contents as string,
|
|
170
|
-
{
|
|
171
|
-
filename: path,
|
|
172
|
-
sourceType: "module",
|
|
173
|
-
plugins: [j2d],
|
|
174
|
-
parserOpts: {
|
|
175
|
-
plugins: ["jsx"],
|
|
176
|
-
},
|
|
177
|
-
configFile: false,
|
|
178
|
-
babelrc: false,
|
|
179
|
-
}
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
return {
|
|
183
|
-
contents: babelResult?.code || "",
|
|
184
|
-
loader: "js",
|
|
185
|
-
resolveDir: swcResult.resolveDir,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
async transformServerComponent(
|
|
190
|
-
node: FileNode,
|
|
191
|
-
source: string,
|
|
192
|
-
path: string
|
|
193
|
-
): Promise<OnLoadResult> {
|
|
194
|
-
const scSource = generateServerComponent(path, source);
|
|
195
|
-
return swcTransform(scSource, path);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async transformPublicFileRsc(
|
|
199
|
-
node: FileNode,
|
|
200
|
-
source: string,
|
|
201
|
-
path: string
|
|
202
|
-
): Promise<OnLoadResult> {
|
|
203
|
-
const stubSource = generateRscStub(path, source);
|
|
204
|
-
return swcTransform(stubSource, path);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
async transformSharedCode(
|
|
208
|
-
source: string,
|
|
209
|
-
path: string
|
|
210
|
-
): Promise<OnLoadResult> {
|
|
211
|
-
return swcTransform(source, path);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
async process(node: FileNode, metadata: FileMetadata): Promise<OnLoadResult> {
|
|
215
|
-
const expandedSource = await expandMacros(metadata.source, metadata.path);
|
|
216
|
-
|
|
217
|
-
const expandedMetadata = { ...metadata, source: expandedSource };
|
|
218
|
-
const { source, path, isTsx, directive } = expandedMetadata;
|
|
219
|
-
|
|
220
|
-
if (isTsx) {
|
|
221
|
-
if (directive === "interactive") {
|
|
222
|
-
return this.transformInteractiveTsx(source, path);
|
|
223
|
-
} else if (directive === null) {
|
|
224
|
-
return this.transformServerComponent(node, source, path);
|
|
225
|
-
} else {
|
|
226
|
-
throw new Error(
|
|
227
|
-
`Unexpected directive "${directive}" for TSX file: ${path}`
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (directive === "public") {
|
|
233
|
-
return this.transformPublicFileRsc(node, source, path);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (directive === null) {
|
|
237
|
-
return this.transformSharedCode(source, path);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return {
|
|
241
|
-
contents: source,
|
|
242
|
-
loader: isTsx ? "tsx" : "ts",
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export function useMyPlugin(options: MyPluginParams): Plugin {
|
|
248
|
-
const serverTransformer = new ServerBuildTransformer();
|
|
249
|
-
const clientTransformer = new ClientBuildTransformer();
|
|
250
|
-
|
|
251
|
-
return {
|
|
252
|
-
name: "Orca",
|
|
253
|
-
setup(build) {
|
|
254
|
-
build.onLoad(
|
|
255
|
-
{ filter: /\.tsx?$/ },
|
|
256
|
-
async (args: OnLoadArgs): Promise<OnLoadResult> => {
|
|
257
|
-
const source = await fs.readFile(args.path, "utf8");
|
|
258
|
-
const metadata = parseFileMetadata(source, args.path);
|
|
259
|
-
|
|
260
|
-
if (options.isServerBuild) {
|
|
261
|
-
return serverTransformer.process(metadata, options.onClientFound);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (!options.graph) {
|
|
265
|
-
throw new Error(
|
|
266
|
-
"Dependency graph is required for client build but was not provided"
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const node = options.graph[args.path];
|
|
271
|
-
|
|
272
|
-
if (!node) {
|
|
273
|
-
console.log(`File node not found in depend graph: ${args.path}`);
|
|
274
|
-
throw new Error("900");
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return clientTransformer.process(node, metadata);
|
|
278
|
-
}
|
|
279
|
-
);
|
|
280
|
-
},
|
|
281
|
-
};
|
|
282
|
-
}
|