transone-cli 0.3.1 → 0.5.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 +17 -6
- package/README.zh-CN.md +18 -5
- package/dist/app/analyze.d.ts +2 -0
- package/dist/app/build-app.d.ts +3 -0
- package/dist/app/dialects.d.ts +4 -0
- package/dist/app/errors.d.ts +1 -0
- package/dist/app/types.d.ts +61 -0
- package/dist/{build-mp-k1dgvwwx.js → build-mp-6j38wf4r.js} +5 -14
- package/dist/{build-mp-k1dgvwwx.js.map → build-mp-6j38wf4r.js.map} +3 -4
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +2 -2
- package/dist/create.d.ts +1 -1
- package/dist/index-k1qfvp0y.js +19 -0
- package/dist/index-k1qfvp0y.js.map +10 -0
- package/dist/{index-rjvspt2q.js → index-nag8rsrg.js} +570 -62
- package/dist/index-nag8rsrg.js.map +27 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +20 -3
- package/dist/index.js.map +4 -3
- package/dist/mp/dialect.d.ts +1 -0
- package/dist/mp/ts-loader.d.ts +1 -1
- package/dist/target/app-target.d.ts +10 -0
- package/dist/target/mp-target.d.ts +1 -0
- package/dist/target/registry.d.ts +2 -2
- package/dist/target/types.d.ts +11 -6
- package/dist/types.d.ts +35 -14
- package/package.json +1 -1
- package/dist/index-rjvspt2q.js.map +0 -23
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
loadTypescript
|
|
4
|
+
} from "./index-k1qfvp0y.js";
|
|
2
5
|
import {
|
|
3
6
|
__require
|
|
4
7
|
} from "./index-yb2wsc7f.js";
|
|
@@ -9,6 +12,7 @@ var TARGET_TYPES = [
|
|
|
9
12
|
"mp-weixin",
|
|
10
13
|
"mp-alipay",
|
|
11
14
|
"mp-bytedance",
|
|
15
|
+
"mp-xiaohongshu",
|
|
12
16
|
"app-ios",
|
|
13
17
|
"app-android",
|
|
14
18
|
"app-harmony"
|
|
@@ -19,8 +23,17 @@ function isTargetType(value) {
|
|
|
19
23
|
var MP_TARGET_TYPES = [
|
|
20
24
|
"mp-weixin",
|
|
21
25
|
"mp-alipay",
|
|
22
|
-
"mp-bytedance"
|
|
26
|
+
"mp-bytedance",
|
|
27
|
+
"mp-xiaohongshu"
|
|
28
|
+
];
|
|
29
|
+
var APP_TARGET_TYPES = [
|
|
30
|
+
"app-ios",
|
|
31
|
+
"app-android",
|
|
32
|
+
"app-harmony"
|
|
23
33
|
];
|
|
34
|
+
function isAppTargetType(value) {
|
|
35
|
+
return typeof value === "string" && APP_TARGET_TYPES.includes(value);
|
|
36
|
+
}
|
|
24
37
|
function isMpTargetType(value) {
|
|
25
38
|
return typeof value === "string" && MP_TARGET_TYPES.includes(value);
|
|
26
39
|
}
|
|
@@ -72,7 +85,8 @@ async function resolveConfig(options = {}) {
|
|
|
72
85
|
includeEntry: false,
|
|
73
86
|
allowRoot: true
|
|
74
87
|
}) : pages;
|
|
75
|
-
const mpEnabled = config.mp !== undefined || target
|
|
88
|
+
const mpEnabled = config.mp !== undefined || isMpTargetType(target);
|
|
89
|
+
const appConfig = pickAppConfig(config.app, target);
|
|
76
90
|
return {
|
|
77
91
|
root,
|
|
78
92
|
...loadedConfig.exists ? { configFile } : {},
|
|
@@ -92,25 +106,64 @@ async function resolveConfig(options = {}) {
|
|
|
92
106
|
...config.library ? { library: resolveLibrary(root, config.library) } : {},
|
|
93
107
|
...mpEnabled ? {
|
|
94
108
|
mp: resolveMiniProgram(root, options.mpOutDir, mpConfig ?? {}, mpPages, target)
|
|
95
|
-
} : {}
|
|
109
|
+
} : {},
|
|
110
|
+
...isAppTargetType(target) ? { app: await resolveApp(root, options.outDir, appConfig ?? {}, target, pages) } : {}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function isAppConfigMap(value) {
|
|
114
|
+
return isRecord(value) && APP_TARGET_TYPES.some((platform) => (platform in value));
|
|
115
|
+
}
|
|
116
|
+
function pickAppConfig(app, target) {
|
|
117
|
+
if (app === undefined) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (isAppConfigMap(app)) {
|
|
121
|
+
return isAppTargetType(target) ? app[target] : undefined;
|
|
122
|
+
}
|
|
123
|
+
return app;
|
|
124
|
+
}
|
|
125
|
+
async function resolveApp(root, outDirOverride, app, target, fallbackPages) {
|
|
126
|
+
return {
|
|
127
|
+
appName: app.appName ?? "TransOne",
|
|
128
|
+
bundleId: app.bundleId ?? "com.transone.app",
|
|
129
|
+
outDir: resolve(root, outDirOverride ?? app.outDir ?? `dist/build/${target}`),
|
|
130
|
+
minPlatformVersion: app.minPlatformVersion ?? "16.0",
|
|
131
|
+
publicDir: resolve(root, app.publicDir ?? "public"),
|
|
132
|
+
pages: app.pages ? await resolvePages(root, resolve(root, app.pages["/"] ?? "src/main.ts"), app.pages, {
|
|
133
|
+
includeEntry: false,
|
|
134
|
+
allowRoot: true
|
|
135
|
+
}) : fallbackPages
|
|
96
136
|
};
|
|
97
137
|
}
|
|
98
138
|
var MP_DEFAULT_OUT_DIRS = {
|
|
99
139
|
"mp-weixin": "dist/build/mp-weixin",
|
|
100
140
|
"mp-alipay": "dist/build/mp-alipay",
|
|
101
|
-
"mp-bytedance": "dist/build/mp-bytedance"
|
|
141
|
+
"mp-bytedance": "dist/build/mp-bytedance",
|
|
142
|
+
"mp-xiaohongshu": "dist/build/mp-xiaohongshu"
|
|
102
143
|
};
|
|
103
|
-
function isMpConfigMap(value) {
|
|
104
|
-
return isRecord(value) && MP_TARGET_TYPES.some((platform) => (platform in value));
|
|
105
|
-
}
|
|
106
144
|
function pickMpConfig(mp, target) {
|
|
107
145
|
if (mp === undefined) {
|
|
108
146
|
return;
|
|
109
147
|
}
|
|
110
|
-
|
|
111
|
-
|
|
148
|
+
const common = Object.fromEntries(Object.entries(mp).filter(([key]) => !MP_TARGET_TYPES.includes(key)));
|
|
149
|
+
const platform = isMpTargetType(target) ? mp[target] : undefined;
|
|
150
|
+
return mergeMpRecords(common, { ...platform });
|
|
151
|
+
}
|
|
152
|
+
function mergeMpRecords(common, overrides) {
|
|
153
|
+
const merged = { ...common };
|
|
154
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
155
|
+
if (value === undefined)
|
|
156
|
+
continue;
|
|
157
|
+
const previous = Object.prototype.hasOwnProperty.call(common, key) ? common[key] : undefined;
|
|
158
|
+
const next = isRecord(previous) && isRecord(value) ? mergeMpRecords(previous, value) : value;
|
|
159
|
+
Object.defineProperty(merged, key, {
|
|
160
|
+
value: next,
|
|
161
|
+
enumerable: true,
|
|
162
|
+
configurable: true,
|
|
163
|
+
writable: true
|
|
164
|
+
});
|
|
112
165
|
}
|
|
113
|
-
return
|
|
166
|
+
return merged;
|
|
114
167
|
}
|
|
115
168
|
function resolveMiniProgram(root, outDirOverride, mp, pages, target) {
|
|
116
169
|
return {
|
|
@@ -154,7 +207,7 @@ function resolveTarget(target) {
|
|
|
154
207
|
if (isTargetType(target)) {
|
|
155
208
|
return target;
|
|
156
209
|
}
|
|
157
|
-
throw new Error(`Unknown build target "${String(target)}". ` + "Available targets: web, mp-weixin, mp-alipay, mp-bytedance, " + "app-ios, app-android, app-harmony.");
|
|
210
|
+
throw new Error(`Unknown build target "${String(target)}". ` + "Available targets: web, mp-weixin, mp-alipay, mp-bytedance, mp-xiaohongshu, " + "app-ios, app-android, app-harmony.");
|
|
158
211
|
}
|
|
159
212
|
async function resolvePages(root, entry, pages, options = {}) {
|
|
160
213
|
const resolved = options.includeEntry === false ? {} : { "/": entry };
|
|
@@ -231,7 +284,8 @@ function mergeConfig(...configs) {
|
|
|
231
284
|
directoryPages: build?.directoryPages ?? merged.build.directoryPages
|
|
232
285
|
},
|
|
233
286
|
library: config.library ?? merged.library,
|
|
234
|
-
mp: config.mp ?? merged.mp
|
|
287
|
+
mp: config.mp ?? merged.mp,
|
|
288
|
+
app: config.app ?? merged.app
|
|
235
289
|
};
|
|
236
290
|
}, DEFAULT_CONFIG);
|
|
237
291
|
}
|
|
@@ -255,19 +309,45 @@ function validateUserConfig(config) {
|
|
|
255
309
|
if (config.mp !== undefined) {
|
|
256
310
|
validateMpConfig(config.mp);
|
|
257
311
|
}
|
|
312
|
+
if (config.app !== undefined) {
|
|
313
|
+
validateAppConfig(config.app);
|
|
314
|
+
}
|
|
258
315
|
}
|
|
259
|
-
function
|
|
260
|
-
assertRecord(
|
|
261
|
-
if (
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
316
|
+
function validateAppConfig(app) {
|
|
317
|
+
assertRecord(app, "Config app");
|
|
318
|
+
if (isAppConfigMap(app)) {
|
|
319
|
+
const flatKeys = ["appName", "bundleId", "outDir", "minPlatformVersion", "publicDir", "pages"];
|
|
320
|
+
if (flatKeys.some((key) => (key in app))) {
|
|
321
|
+
throw new Error("Config app cannot mix flat fields with platform keys");
|
|
322
|
+
}
|
|
323
|
+
for (const platform of APP_TARGET_TYPES) {
|
|
324
|
+
if (app[platform] !== undefined) {
|
|
325
|
+
validateSingleAppConfig(app[platform], `Config app.${platform}`);
|
|
266
326
|
}
|
|
267
327
|
}
|
|
268
328
|
return;
|
|
269
329
|
}
|
|
330
|
+
validateSingleAppConfig(app, "Config app");
|
|
331
|
+
}
|
|
332
|
+
function validateSingleAppConfig(app, label) {
|
|
333
|
+
assertRecord(app, label);
|
|
334
|
+
for (const key of ["appName", "bundleId", "outDir", "minPlatformVersion", "publicDir"]) {
|
|
335
|
+
if (app[key] !== undefined && typeof app[key] !== "string") {
|
|
336
|
+
throw new Error(`${label}.${key} must be a string`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (app.pages !== undefined) {
|
|
340
|
+
validatePagesConfig(app.pages, `${label}.pages`);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function validateMpConfig(mp) {
|
|
344
|
+
assertRecord(mp, "Config mp");
|
|
270
345
|
validateMiniProgramConfig(mp, "Config mp");
|
|
346
|
+
for (const platform of MP_TARGET_TYPES) {
|
|
347
|
+
if (mp[platform] !== undefined) {
|
|
348
|
+
validateMiniProgramConfig(mp[platform], `Config mp.${platform}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
271
351
|
}
|
|
272
352
|
function validateMiniProgramConfig(mp, label) {
|
|
273
353
|
assertRecord(mp, label);
|
|
@@ -707,6 +787,35 @@ var MP_BYTEDANCE_DIALECT = {
|
|
|
707
787
|
usingComponents
|
|
708
788
|
})
|
|
709
789
|
};
|
|
790
|
+
var MP_XIAOHONGSHU_DIALECT = {
|
|
791
|
+
id: "mp-xiaohongshu",
|
|
792
|
+
label: "\u5C0F\u7EA2\u4E66\u5C0F\u7A0B\u5E8F\u539F\u751F\u5DE5\u7A0B\uFF08XHSML / CSS / JS \u9759\u6001\u8F6C\u6362\uFF09",
|
|
793
|
+
templateExt: "xhsml",
|
|
794
|
+
styleExt: "css",
|
|
795
|
+
appStyleFile: "app.css",
|
|
796
|
+
directivePrefix: "xhs:",
|
|
797
|
+
bindEvent: (event) => `bind${event}`,
|
|
798
|
+
catchEvent: (event) => `catch${event}`,
|
|
799
|
+
projectConfigFile: "project.config.json",
|
|
800
|
+
buildProjectConfig: (mp, projectName) => ({
|
|
801
|
+
appid: mp.appId,
|
|
802
|
+
projectname: projectName,
|
|
803
|
+
compileType: "miniprogram"
|
|
804
|
+
}),
|
|
805
|
+
windowDefaults: (title) => ({
|
|
806
|
+
navigationBarTitleText: title,
|
|
807
|
+
navigationBarBackgroundColor: "#ffffff",
|
|
808
|
+
navigationBarTextStyle: "black",
|
|
809
|
+
backgroundTextStyle: "light"
|
|
810
|
+
}),
|
|
811
|
+
appJsonExtras: () => ({}),
|
|
812
|
+
sitemap: false,
|
|
813
|
+
componentJson: (usingComponents) => ({
|
|
814
|
+
component: true,
|
|
815
|
+
multipleSlots: true,
|
|
816
|
+
usingComponents
|
|
817
|
+
})
|
|
818
|
+
};
|
|
710
819
|
|
|
711
820
|
// src/target/mp-target.ts
|
|
712
821
|
class MpTarget {
|
|
@@ -724,29 +833,427 @@ class MpTarget {
|
|
|
724
833
|
if (!config.mp) {
|
|
725
834
|
throw new Error("Mini program build requires config.mp\uFF08\u8BF7\u5728 transone.config.ts \u914D\u7F6E mp \u5B57\u6BB5\uFF0C" + "\u5982 appId / pages / outDir\uFF09");
|
|
726
835
|
}
|
|
727
|
-
const { buildMiniProgram } = await import("./build-mp-
|
|
836
|
+
const { buildMiniProgram } = await import("./build-mp-6j38wf4r.js");
|
|
728
837
|
return buildMiniProgram(config, this.dialect);
|
|
729
838
|
}
|
|
730
839
|
}
|
|
731
840
|
var mpWeixinTarget = new MpTarget(MP_WEIXIN_DIALECT);
|
|
732
841
|
var mpAlipayTarget = new MpTarget(MP_ALIPAY_DIALECT);
|
|
733
842
|
var mpBytedanceTarget = new MpTarget(MP_BYTEDANCE_DIALECT);
|
|
843
|
+
var mpXiaohongshuTarget = new MpTarget(MP_XIAOHONGSHU_DIALECT);
|
|
844
|
+
|
|
845
|
+
// src/app/build-app.ts
|
|
846
|
+
import { cp, mkdir as mkdir2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
847
|
+
import { existsSync as existsSync3 } from "fs";
|
|
848
|
+
import { dirname as dirname3, join, resolve as resolve4 } from "path";
|
|
734
849
|
|
|
735
|
-
// src/
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
850
|
+
// src/app/errors.ts
|
|
851
|
+
import { basename } from "path";
|
|
852
|
+
function nativeError(filePath, message) {
|
|
853
|
+
return new Error(`[transone app] ${basename(filePath)}: ${message}`);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// src/app/analyze.ts
|
|
857
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
858
|
+
var CONTAINERS = new Set(["view", "main", "div"]);
|
|
859
|
+
var TEXT = new Set(["text", "span", "p", "h1"]);
|
|
860
|
+
var STYLE_KEYS = new Set(["color", "backgroundColor", "fontSize", "fontWeight", "padding", "margin", "width", "height", "borderRadius", "textAlign"]);
|
|
861
|
+
async function analyzeNativeScreen(entry) {
|
|
862
|
+
if (!existsSync2(entry))
|
|
863
|
+
throw nativeError(entry, "\u6E90\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
864
|
+
const ts = await loadTypescript();
|
|
865
|
+
const source = ts.createSourceFile(entry, readFileSync(entry, "utf8"), ts.ScriptTarget.Latest, true);
|
|
866
|
+
const component = source.statements.find((s) => ts.isClassDeclaration(s));
|
|
867
|
+
if (!component)
|
|
868
|
+
throw nativeError(entry, "\u672A\u627E\u5230 Component \u7C7B");
|
|
869
|
+
const state = readState(ts, component, entry);
|
|
870
|
+
const actions = new Map;
|
|
871
|
+
for (const member of component.members)
|
|
872
|
+
if (ts.isMethodDeclaration(member) && ts.isIdentifier(member.name)) {
|
|
873
|
+
const action = readAction(ts, member, entry);
|
|
874
|
+
if (action)
|
|
875
|
+
actions.set(member.name.text, action);
|
|
876
|
+
}
|
|
877
|
+
const render = component.members.find((m) => ts.isMethodDeclaration(m) && m.name.getText(source) === "render");
|
|
878
|
+
const value = render?.body?.statements.find(ts.isReturnStatement)?.expression;
|
|
879
|
+
if (!value || !ts.isObjectLiteralExpression(value))
|
|
880
|
+
throw nativeError(entry, "render() \u5FC5\u987B\u8FD4\u56DE\u9759\u6001 VNode \u5BF9\u8C61");
|
|
881
|
+
const root = readNode(ts, value, entry, new Set(state.map((item) => item.key)), actions);
|
|
882
|
+
if (root.kind !== "container")
|
|
883
|
+
throw nativeError(entry, "\u6839\u8282\u70B9\u5FC5\u987B\u662F\u5BB9\u5668\u8282\u70B9");
|
|
884
|
+
return { name: component.name?.text ?? "App", state, root };
|
|
885
|
+
}
|
|
886
|
+
function readState(ts, component, file) {
|
|
887
|
+
const method = component.members.find((m) => ts.isMethodDeclaration(m) && m.name.getText() === "initState");
|
|
888
|
+
const value = method?.body?.statements.find(ts.isReturnStatement)?.expression;
|
|
889
|
+
if (!value)
|
|
890
|
+
return [];
|
|
891
|
+
if (!ts.isObjectLiteralExpression(value))
|
|
892
|
+
throw nativeError(file, "initState() \u5FC5\u987B\u8FD4\u56DE\u5BF9\u8C61\u5B57\u9762\u91CF");
|
|
893
|
+
return value.properties.map((item) => {
|
|
894
|
+
if (!ts.isPropertyAssignment(item) || !ts.isIdentifier(item.name))
|
|
895
|
+
throw nativeError(file, "state \u5FC5\u987B\u4F7F\u7528\u6807\u8BC6\u7B26\u5C5E\u6027");
|
|
896
|
+
const literal = literalValue(ts, item.initializer);
|
|
897
|
+
if (literal === undefined)
|
|
898
|
+
throw nativeError(file, `state.${item.name.text} \u5FC5\u987B\u662F\u5B57\u9762\u91CF`);
|
|
899
|
+
return { key: item.name.text, value: literal };
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
function readAction(ts, method, file) {
|
|
903
|
+
const expression = method.body?.statements[0];
|
|
904
|
+
if (!expression || !ts.isExpressionStatement(expression) || !ts.isBinaryExpression(expression.expression))
|
|
905
|
+
return;
|
|
906
|
+
const binary = expression.expression;
|
|
907
|
+
if (!ts.isPropertyAccessExpression(binary.left) || !ts.isPropertyAccessExpression(binary.left.expression) || binary.left.expression.expression.kind !== ts.SyntaxKind.ThisKeyword || binary.left.expression.name.text !== "state")
|
|
908
|
+
return;
|
|
909
|
+
const value = literalValue(ts, binary.right);
|
|
910
|
+
const key = binary.left.name.text;
|
|
911
|
+
if ((binary.operatorToken.kind === ts.SyntaxKind.PlusEqualsToken || binary.operatorToken.kind === ts.SyntaxKind.MinusEqualsToken) && typeof value === "number")
|
|
912
|
+
return { kind: "increment", key, by: binary.operatorToken.kind === ts.SyntaxKind.MinusEqualsToken ? -value : value };
|
|
913
|
+
if (binary.operatorToken.kind === ts.SyntaxKind.EqualsToken && value !== undefined)
|
|
914
|
+
return { kind: "set-literal", key, value };
|
|
915
|
+
throw nativeError(file, `\u65B9\u6CD5 ${method.name.getText()} \u4E0D\u652F\u6301\u539F\u751F\u7F16\u8BD1`);
|
|
916
|
+
}
|
|
917
|
+
function readNode(ts, node, file, state, actions) {
|
|
918
|
+
const tag = stringValue(ts, get(ts, node, "tag"), file, "VNode tag");
|
|
919
|
+
const style = readStyle(ts, get(ts, node, "props"), file);
|
|
920
|
+
const children = get(ts, node, "children");
|
|
921
|
+
const childNodes = children && ts.isArrayLiteralExpression(children) ? [...children.elements].filter(ts.isExpression) : [];
|
|
922
|
+
if (CONTAINERS.has(tag))
|
|
923
|
+
return { kind: "container", children: childNodes.map((child) => {
|
|
924
|
+
if (!ts.isObjectLiteralExpression(child))
|
|
925
|
+
throw nativeError(file, "\u5BB9\u5668 children \u53EA\u652F\u6301\u9759\u6001 VNode");
|
|
926
|
+
return readNode(ts, child, file, state, actions);
|
|
927
|
+
}), ...style ? { style } : {} };
|
|
928
|
+
const parts = childNodes.flatMap((child) => readText(ts, child, file, state));
|
|
929
|
+
if (TEXT.has(tag))
|
|
930
|
+
return { kind: "text", parts, ...style ? { style } : {} };
|
|
931
|
+
if (tag === "button")
|
|
932
|
+
return { kind: "button", parts, action: readClick(ts, get(ts, node, "listeners"), file, actions), ...style ? { style } : {} };
|
|
933
|
+
throw nativeError(file, `\u4E0D\u652F\u6301\u7684\u539F\u751F\u8282\u70B9: ${tag}`);
|
|
934
|
+
}
|
|
935
|
+
function readText(ts, expression, file, state) {
|
|
936
|
+
const value = literalValue(ts, expression);
|
|
937
|
+
if (typeof value !== "string")
|
|
938
|
+
throw nativeError(file, "\u6587\u672C children \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u5B57\u9762\u91CF");
|
|
939
|
+
const result = [];
|
|
940
|
+
const matcher = /{{([^}]+)}}/g;
|
|
941
|
+
let cursor = 0;
|
|
942
|
+
let match;
|
|
943
|
+
while (match = matcher.exec(value)) {
|
|
944
|
+
if (match.index > cursor)
|
|
945
|
+
result.push({ kind: "literal", value: value.slice(cursor, match.index) });
|
|
946
|
+
const key = match[1];
|
|
947
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(key) || !state.has(key))
|
|
948
|
+
throw nativeError(file, "\u53EA\u652F\u6301\u5DF2\u58F0\u660E state \u7684 {{key}} \u7ED1\u5B9A");
|
|
949
|
+
result.push({ kind: "state", key });
|
|
950
|
+
cursor = matcher.lastIndex;
|
|
951
|
+
}
|
|
952
|
+
if (cursor < value.length || result.length === 0)
|
|
953
|
+
result.push({ kind: "literal", value: value.slice(cursor) });
|
|
954
|
+
return result;
|
|
955
|
+
}
|
|
956
|
+
function readClick(ts, listeners, file, actions) {
|
|
957
|
+
if (!listeners || !ts.isObjectLiteralExpression(listeners))
|
|
958
|
+
throw nativeError(file, "button \u5FC5\u987B\u58F0\u660E listeners.click");
|
|
959
|
+
const handler = get(ts, listeners, "click");
|
|
960
|
+
const body = handler && ts.isArrowFunction(handler) ? handler.body : undefined;
|
|
961
|
+
const expression = body && ts.isCallExpression(body) ? body : body && ts.isBlock(body) && ts.isExpressionStatement(body.statements[0]) ? body.statements[0].expression : undefined;
|
|
962
|
+
if (!expression || !ts.isCallExpression(expression) || !ts.isPropertyAccessExpression(expression.expression) || expression.expression.expression.kind !== ts.SyntaxKind.ThisKeyword)
|
|
963
|
+
throw nativeError(file, "click \u53EA\u652F\u6301\u8C03\u7528 this.method()");
|
|
964
|
+
const action = actions.get(expression.expression.name.text);
|
|
965
|
+
if (!action)
|
|
966
|
+
throw nativeError(file, `click \u65B9\u6CD5 ${expression.expression.name.text} \u4E0D\u652F\u6301\u539F\u751F\u7F16\u8BD1`);
|
|
967
|
+
return action;
|
|
968
|
+
}
|
|
969
|
+
function readStyle(ts, props, file) {
|
|
970
|
+
if (!props || !ts.isObjectLiteralExpression(props))
|
|
971
|
+
return;
|
|
972
|
+
const style = get(ts, props, "style");
|
|
973
|
+
if (!style || !ts.isObjectLiteralExpression(style))
|
|
974
|
+
return;
|
|
975
|
+
const out = {};
|
|
976
|
+
for (const item of style.properties) {
|
|
977
|
+
if (!ts.isPropertyAssignment(item) || !ts.isIdentifier(item.name) || !STYLE_KEYS.has(item.name.text))
|
|
978
|
+
throw nativeError(file, "\u4E0D\u652F\u6301\u7684\u539F\u751F\u6837\u5F0F\u5C5E\u6027");
|
|
979
|
+
const value = literalValue(ts, item.initializer);
|
|
980
|
+
const keyword = item.name.text === "color" || item.name.text === "backgroundColor" || item.name.text === "fontWeight" || item.name.text === "textAlign";
|
|
981
|
+
if (keyword && (typeof value === "string" || typeof value === "number")) {
|
|
982
|
+
out[item.name.text] = value;
|
|
983
|
+
continue;
|
|
984
|
+
}
|
|
985
|
+
if (typeof value !== "number" && !(typeof value === "string" && /^\d+(\.\d+)?px$/.test(value)))
|
|
986
|
+
throw nativeError(file, `\u6837\u5F0F ${item.name.text} \u53EA\u652F\u6301\u6570\u5B57\u6216 px`);
|
|
987
|
+
out[item.name.text] = typeof value === "string" ? Number.parseFloat(value) : value;
|
|
988
|
+
}
|
|
989
|
+
return out;
|
|
990
|
+
}
|
|
991
|
+
function get(ts, node, name) {
|
|
992
|
+
const item = node.properties.find((p) => ts.isPropertyAssignment(p) && p.name.getText().replace(/['"]/g, "") === name);
|
|
993
|
+
return item && ts.isPropertyAssignment(item) ? item.initializer : undefined;
|
|
994
|
+
}
|
|
995
|
+
function stringValue(ts, expression, file, label) {
|
|
996
|
+
const value = expression && literalValue(ts, expression);
|
|
997
|
+
if (typeof value !== "string")
|
|
998
|
+
throw nativeError(file, `${label} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
|
|
999
|
+
return value;
|
|
1000
|
+
}
|
|
1001
|
+
function literalValue(ts, value) {
|
|
1002
|
+
if (ts.isStringLiteral(value) || ts.isNoSubstitutionTemplateLiteral(value))
|
|
1003
|
+
return value.text;
|
|
1004
|
+
if (ts.isNumericLiteral(value))
|
|
1005
|
+
return Number(value.text);
|
|
1006
|
+
if (value.kind === ts.SyntaxKind.TrueKeyword)
|
|
1007
|
+
return true;
|
|
1008
|
+
if (value.kind === ts.SyntaxKind.FalseKeyword)
|
|
1009
|
+
return false;
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// src/app/build-app.ts
|
|
1014
|
+
async function buildNativeApp(config, dialect) {
|
|
1015
|
+
if (!config.app)
|
|
1016
|
+
throw new Error("Native app build requires config.app");
|
|
1017
|
+
const entries = Object.values(config.app.pages);
|
|
1018
|
+
if (entries.length !== 1)
|
|
1019
|
+
throw nativeError(config.entry, "\u9996\u671F\u539F\u751F App \u53EA\u652F\u6301\u4E00\u4E2A\u9875\u9762");
|
|
1020
|
+
const screen = await analyzeNativeScreen(entries[0]);
|
|
1021
|
+
const files = dialect.generateProject(screen, config.app);
|
|
1022
|
+
await rm2(config.app.outDir, { recursive: true, force: true });
|
|
1023
|
+
const assetsBuilt = [];
|
|
1024
|
+
for (const [relative3, content] of Object.entries(files).sort(([a], [b]) => a.localeCompare(b))) {
|
|
1025
|
+
const target = join(config.app.outDir, relative3);
|
|
1026
|
+
await mkdir2(dirname3(target), { recursive: true });
|
|
1027
|
+
await writeFile2(target, content, "utf8");
|
|
1028
|
+
assetsBuilt.push(target);
|
|
1029
|
+
}
|
|
1030
|
+
if (existsSync3(config.app.publicDir))
|
|
1031
|
+
await cp(config.app.publicDir, join(config.app.outDir, dialect.resourceDirectory), { recursive: true });
|
|
1032
|
+
return { root: config.root, outDir: resolve4(config.app.outDir), assetsBuilt };
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// src/target/app-target.ts
|
|
1036
|
+
class AppTarget {
|
|
1037
|
+
dialect;
|
|
1038
|
+
constructor(dialect) {
|
|
1039
|
+
this.dialect = dialect;
|
|
1040
|
+
}
|
|
1041
|
+
get type() {
|
|
1042
|
+
return this.dialect.id;
|
|
1043
|
+
}
|
|
1044
|
+
get label() {
|
|
1045
|
+
return this.dialect.label;
|
|
1046
|
+
}
|
|
1047
|
+
build(config, _options) {
|
|
1048
|
+
return buildNativeApp(config, this.dialect);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// src/app/dialects.ts
|
|
1053
|
+
function text(parts, language) {
|
|
1054
|
+
if (language === "swift") {
|
|
1055
|
+
const value = parts.map((part) => part.kind === "literal" ? part.value : `\\(${part.key})`).join("");
|
|
1056
|
+
return `"${value.replace(/"/g, "\\\"")}"`;
|
|
1057
|
+
}
|
|
1058
|
+
if (language === "kotlin") {
|
|
1059
|
+
return JSON.stringify(parts.map((part) => part.kind === "literal" ? part.value : `$${part.key}`).join(""));
|
|
1060
|
+
}
|
|
1061
|
+
return parts.map((part) => part.kind === "literal" ? JSON.stringify(part.value) : `this.${part.key}`).join(" + ") || '""';
|
|
1062
|
+
}
|
|
1063
|
+
function action(node, language) {
|
|
1064
|
+
const { action: action2 } = node;
|
|
1065
|
+
const target = language === "ark" ? `this.${action2.key}` : action2.key;
|
|
1066
|
+
return action2.kind === "increment" ? `${target} ${action2.by >= 0 ? "+=" : "-="} ${Math.abs(action2.by)}` : `${target} = ${typeof action2.value === "string" ? JSON.stringify(action2.value) : action2.value}`;
|
|
1067
|
+
}
|
|
1068
|
+
function swiftNode(node, indent = " ") {
|
|
1069
|
+
if (node.kind === "container")
|
|
1070
|
+
return `${indent}VStack {
|
|
1071
|
+
${node.children.map((child) => swiftNode(child, `${indent} `)).join(`
|
|
1072
|
+
`)}
|
|
1073
|
+
${indent}}`;
|
|
1074
|
+
if (node.kind === "text")
|
|
1075
|
+
return `${indent}Text(${text(node.parts, "swift")})`;
|
|
1076
|
+
return `${indent}Button(${text(node.parts, "swift")}) { ${action(node, "swift")} }`;
|
|
1077
|
+
}
|
|
1078
|
+
function kotlinNode(node, indent = " ") {
|
|
1079
|
+
if (node.kind === "container")
|
|
1080
|
+
return `${indent}Column {
|
|
1081
|
+
${node.children.map((child) => kotlinNode(child, `${indent} `)).join(`
|
|
1082
|
+
`)}
|
|
1083
|
+
${indent}}`;
|
|
1084
|
+
if (node.kind === "text")
|
|
1085
|
+
return `${indent}Text(${text(node.parts, "kotlin")})`;
|
|
1086
|
+
return `${indent}Button(onClick = { ${action(node, "kotlin")} }) { Text(${text(node.parts, "kotlin")}) }`;
|
|
1087
|
+
}
|
|
1088
|
+
function arkNode(node, indent = " ") {
|
|
1089
|
+
if (node.kind === "container")
|
|
1090
|
+
return `${indent}Column() {
|
|
1091
|
+
${node.children.map((child) => arkNode(child, `${indent} `)).join(`
|
|
1092
|
+
`)}
|
|
1093
|
+
${indent}}`;
|
|
1094
|
+
if (node.kind === "text")
|
|
1095
|
+
return `${indent}Text(${text(node.parts, "ark")})`;
|
|
1096
|
+
return `${indent}Button(${text(node.parts, "ark")}).onClick(() => { ${action(node, "ark")} })`;
|
|
1097
|
+
}
|
|
1098
|
+
function swiftState(screen) {
|
|
1099
|
+
return screen.state.map((item) => ` @State private var ${item.key}: ${typeof item.value === "number" ? "Int" : typeof item.value === "boolean" ? "Bool" : "String"} = ${JSON.stringify(item.value)}`).join(`
|
|
1100
|
+
`);
|
|
1101
|
+
}
|
|
1102
|
+
function kotlinState(screen) {
|
|
1103
|
+
return screen.state.map((item) => ` var ${item.key} by remember { mutableStateOf(${JSON.stringify(item.value)}) }`).join(`
|
|
1104
|
+
`);
|
|
1105
|
+
}
|
|
1106
|
+
function arkState(screen) {
|
|
1107
|
+
return screen.state.map((item) => ` @State ${item.key}: ${typeof item.value === "number" ? "number" : typeof item.value === "boolean" ? "boolean" : "string"} = ${JSON.stringify(item.value)}`).join(`
|
|
1108
|
+
`);
|
|
1109
|
+
}
|
|
1110
|
+
var IOS_DIALECT = {
|
|
1111
|
+
id: "app-ios",
|
|
1112
|
+
label: "iOS \u539F\u751F App\uFF08SwiftUI\uFF09",
|
|
1113
|
+
resourceDirectory: "TransOneApp/Assets",
|
|
1114
|
+
generateProject(screen, config) {
|
|
1115
|
+
return {
|
|
1116
|
+
"TransOneApp/TransOneApp.swift": `import SwiftUI
|
|
1117
|
+
|
|
1118
|
+
@main struct TransOneApp: App { var body: some Scene { WindowGroup { ContentView() } } }
|
|
1119
|
+
`,
|
|
1120
|
+
"TransOneApp/ContentView.swift": `import SwiftUI
|
|
1121
|
+
|
|
1122
|
+
struct ContentView: View {
|
|
1123
|
+
${swiftState(screen)}
|
|
1124
|
+
var body: some View {
|
|
1125
|
+
${swiftNode(screen.root)}
|
|
744
1126
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
1127
|
+
}
|
|
1128
|
+
`,
|
|
1129
|
+
"TransOneApp.xcodeproj/project.pbxproj": xcodeProject(config),
|
|
1130
|
+
"TransOneApp/Assets.xcassets/Contents.json": `{"info":{"author":"xcode","version":1}}
|
|
1131
|
+
`
|
|
1132
|
+
};
|
|
748
1133
|
}
|
|
1134
|
+
};
|
|
1135
|
+
function xcodeProject(config) {
|
|
1136
|
+
const escapedName = config.appName.replace(/"/g, "\\\"");
|
|
1137
|
+
return `// !$*UTF8*$!
|
|
1138
|
+
{
|
|
1139
|
+
archiveVersion = 1;
|
|
1140
|
+
classes = {};
|
|
1141
|
+
objectVersion = 56;
|
|
1142
|
+
objects = {
|
|
1143
|
+
|
|
1144
|
+
/* Begin PBXBuildFile section */
|
|
1145
|
+
A00100000000000000000001 /* TransOneApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A00100000000000000000011 /* TransOneApp.swift */; };
|
|
1146
|
+
A00100000000000000000002 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A00100000000000000000012 /* ContentView.swift */; };
|
|
1147
|
+
/* End PBXBuildFile section */
|
|
1148
|
+
|
|
1149
|
+
/* Begin PBXFileReference section */
|
|
1150
|
+
A00100000000000000000011 /* TransOneApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransOneApp.swift; sourceTree = "<group>"; };
|
|
1151
|
+
A00100000000000000000012 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
|
1152
|
+
A00100000000000000000013 /* TransOneApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TransOneApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
1153
|
+
/* End PBXFileReference section */
|
|
1154
|
+
|
|
1155
|
+
/* Begin PBXGroup section */
|
|
1156
|
+
A00100000000000000000021 = {isa = PBXGroup; children = (A00100000000000000000022 /* TransOneApp */, A00100000000000000000023 /* Products */, ); sourceTree = "<group>"; };
|
|
1157
|
+
A00100000000000000000022 /* TransOneApp */ = {isa = PBXGroup; children = (A00100000000000000000011 /* TransOneApp.swift */, A00100000000000000000012 /* ContentView.swift */, ); path = TransOneApp; sourceTree = "<group>"; };
|
|
1158
|
+
A00100000000000000000023 /* Products */ = {isa = PBXGroup; children = (A00100000000000000000013 /* TransOneApp.app */, ); name = Products; sourceTree = "<group>"; };
|
|
1159
|
+
/* End PBXGroup section */
|
|
1160
|
+
|
|
1161
|
+
/* Begin PBXNativeTarget section */
|
|
1162
|
+
A00100000000000000000031 /* TransOneApp */ = {isa = PBXNativeTarget; buildConfigurationList = A00100000000000000000041 /* Build configuration list for PBXNativeTarget "TransOneApp" */; buildPhases = (A00100000000000000000032 /* Sources */, A00100000000000000000033 /* Frameworks */, A00100000000000000000034 /* Resources */, ); buildRules = (); dependencies = (); name = TransOneApp; productName = TransOneApp; productReference = A00100000000000000000013 /* TransOneApp.app */; productType = "com.apple.product-type.application"; };
|
|
1163
|
+
/* End PBXNativeTarget section */
|
|
1164
|
+
|
|
1165
|
+
/* Begin PBXProject section */
|
|
1166
|
+
A00100000000000000000051 /* Project object */ = {isa = PBXProject; attributes = { LastUpgradeCheck = 2700; TargetAttributes = { A00100000000000000000031 = { CreatedOnToolsVersion = 27.0; }; }; }; buildConfigurationList = A00100000000000000000052 /* Build configuration list for PBXProject "TransOneApp" */; compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = (en, Base, ); mainGroup = A00100000000000000000021; productRefGroup = A00100000000000000000023; projectDirPath = ""; projectRoot = ""; targets = (A00100000000000000000031 /* TransOneApp */, ); };
|
|
1167
|
+
/* End PBXProject section */
|
|
1168
|
+
|
|
1169
|
+
/* Begin PBXResourcesBuildPhase section */
|
|
1170
|
+
A00100000000000000000034 /* Resources */ = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; };
|
|
1171
|
+
/* End PBXResourcesBuildPhase section */
|
|
1172
|
+
|
|
1173
|
+
/* Begin PBXSourcesBuildPhase section */
|
|
1174
|
+
A00100000000000000000032 /* Sources */ = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (A00100000000000000000001 /* TransOneApp.swift in Sources */, A00100000000000000000002 /* ContentView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };
|
|
1175
|
+
/* End PBXSourcesBuildPhase section */
|
|
1176
|
+
|
|
1177
|
+
/* Begin PBXFrameworksBuildPhase section */
|
|
1178
|
+
A00100000000000000000033 /* Frameworks */ = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; };
|
|
1179
|
+
/* End PBXFrameworksBuildPhase section */
|
|
1180
|
+
|
|
1181
|
+
/* Begin XCBuildConfiguration section */
|
|
1182
|
+
A00100000000000000000061 /* Debug */ = {isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; SWIFT_VERSION = 5.0; }; name = Debug; };
|
|
1183
|
+
A00100000000000000000062 /* Release */ = {isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; SWIFT_VERSION = 5.0; }; name = Release; };
|
|
1184
|
+
A00100000000000000000063 /* Debug */ = {isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CODE_SIGNING_ALLOWED = NO; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = ${config.minPlatformVersion}; PRODUCT_BUNDLE_IDENTIFIER = ${config.bundleId}; PRODUCT_NAME = "${escapedName}"; SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; };
|
|
1185
|
+
A00100000000000000000064 /* Release */ = {isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CODE_SIGNING_ALLOWED = NO; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = ${config.minPlatformVersion}; PRODUCT_BUNDLE_IDENTIFIER = ${config.bundleId}; PRODUCT_NAME = "${escapedName}"; SDKROOT = iphoneos; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; };
|
|
1186
|
+
/* End XCBuildConfiguration section */
|
|
1187
|
+
|
|
1188
|
+
/* Begin XCConfigurationList section */
|
|
1189
|
+
A00100000000000000000041 /* Build configuration list for PBXNativeTarget "TransOneApp" */ = {isa = XCConfigurationList; buildConfigurations = (A00100000000000000000063 /* Debug */, A00100000000000000000064 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; };
|
|
1190
|
+
A00100000000000000000052 /* Build configuration list for PBXProject "TransOneApp" */ = {isa = XCConfigurationList; buildConfigurations = (A00100000000000000000061 /* Debug */, A00100000000000000000062 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; };
|
|
1191
|
+
/* End XCConfigurationList section */
|
|
1192
|
+
};
|
|
1193
|
+
rootObject = A00100000000000000000051 /* Project object */;
|
|
749
1194
|
}
|
|
1195
|
+
`;
|
|
1196
|
+
}
|
|
1197
|
+
var ANDROID_DIALECT = {
|
|
1198
|
+
id: "app-android",
|
|
1199
|
+
label: "Android \u539F\u751F App\uFF08Jetpack Compose\uFF09",
|
|
1200
|
+
resourceDirectory: "app/src/main/assets",
|
|
1201
|
+
generateProject(screen, config) {
|
|
1202
|
+
const pkg = config.bundleId.replace(/[^A-Za-z0-9_.]/g, "_");
|
|
1203
|
+
const path = pkg.replace(/\./g, "/");
|
|
1204
|
+
return {
|
|
1205
|
+
"settings.gradle.kts": `rootProject.name = "${config.appName}"
|
|
1206
|
+
include(":app")
|
|
1207
|
+
`,
|
|
1208
|
+
"build.gradle.kts": `plugins { }
|
|
1209
|
+
`,
|
|
1210
|
+
"app/build.gradle.kts": `plugins { id("com.android.application") version "8.5.0" apply false }
|
|
1211
|
+
`,
|
|
1212
|
+
"app/src/main/AndroidManifest.xml": `<manifest package="${pkg}" xmlns:android="http://schemas.android.com/apk/res/android"><application android:label="${config.appName}"><activity android:name=".MainActivity" android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity></application></manifest>
|
|
1213
|
+
`,
|
|
1214
|
+
[`app/src/main/java/${path}/MainActivity.kt`]: `package ${pkg}
|
|
1215
|
+
|
|
1216
|
+
import androidx.activity.ComponentActivity
|
|
1217
|
+
import androidx.activity.compose.setContent
|
|
1218
|
+
import androidx.compose.runtime.*
|
|
1219
|
+
import androidx.compose.foundation.layout.Column
|
|
1220
|
+
import androidx.compose.material3.*
|
|
1221
|
+
|
|
1222
|
+
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: android.os.Bundle?) { super.onCreate(savedInstanceState); setContent {
|
|
1223
|
+
${kotlinState(screen)}
|
|
1224
|
+
${kotlinNode(screen.root)}
|
|
1225
|
+
} } }
|
|
1226
|
+
`
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
var HARMONY_DIALECT = {
|
|
1231
|
+
id: "app-harmony",
|
|
1232
|
+
label: "HarmonyOS \u539F\u751F App\uFF08ArkUI\uFF09",
|
|
1233
|
+
resourceDirectory: "entry/src/main/resources/rawfile",
|
|
1234
|
+
generateProject(screen, config) {
|
|
1235
|
+
return {
|
|
1236
|
+
"AppScope/app.json5": `{ "app": { "bundleName": "${config.bundleId}", "vendor": "TransOne", "versionCode": 1, "versionName": "1.0.0" } }
|
|
1237
|
+
`,
|
|
1238
|
+
"AppScope/resources/base/element/string.json": `{ "string": [{ "name": "app_name", "value": "${config.appName}" }] }
|
|
1239
|
+
`,
|
|
1240
|
+
"entry/src/main/module.json5": `{ "module": { "name": "entry", "type": "entry", "mainElement": "EntryAbility" } }
|
|
1241
|
+
`,
|
|
1242
|
+
"entry/src/main/ets/entryability/EntryAbility.ets": `import UIAbility from '@ohos.app.ability.UIAbility';
|
|
1243
|
+
export default class EntryAbility extends UIAbility {}
|
|
1244
|
+
`,
|
|
1245
|
+
"entry/src/main/ets/pages/Index.ets": `@Entry
|
|
1246
|
+
@Component
|
|
1247
|
+
struct Index {
|
|
1248
|
+
${arkState(screen)}
|
|
1249
|
+
build() {
|
|
1250
|
+
${arkNode(screen.root)}
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
`
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
750
1257
|
|
|
751
1258
|
// src/target/registry.ts
|
|
752
1259
|
class TargetRegistry {
|
|
@@ -756,9 +1263,10 @@ class TargetRegistry {
|
|
|
756
1263
|
this.register(mpWeixinTarget);
|
|
757
1264
|
this.register(mpAlipayTarget);
|
|
758
1265
|
this.register(mpBytedanceTarget);
|
|
759
|
-
this.register(
|
|
760
|
-
this.register(new
|
|
761
|
-
this.register(new
|
|
1266
|
+
this.register(mpXiaohongshuTarget);
|
|
1267
|
+
this.register(new AppTarget(IOS_DIALECT));
|
|
1268
|
+
this.register(new AppTarget(ANDROID_DIALECT));
|
|
1269
|
+
this.register(new AppTarget(HARMONY_DIALECT));
|
|
762
1270
|
}
|
|
763
1271
|
register(target) {
|
|
764
1272
|
this.targets.set(target.type, target);
|
|
@@ -777,8 +1285,8 @@ class TargetRegistry {
|
|
|
777
1285
|
var targetRegistry = new TargetRegistry;
|
|
778
1286
|
|
|
779
1287
|
// src/build.ts
|
|
780
|
-
import { mkdir as
|
|
781
|
-
import { dirname as
|
|
1288
|
+
import { mkdir as mkdir3, rm as rm3 } from "fs/promises";
|
|
1289
|
+
import { dirname as dirname4, resolve as resolve5 } from "path";
|
|
782
1290
|
async function build(options = {}) {
|
|
783
1291
|
const config = await resolveConfig(options);
|
|
784
1292
|
if (options.library) {
|
|
@@ -792,8 +1300,8 @@ async function buildLibrary(config) {
|
|
|
792
1300
|
if (!library) {
|
|
793
1301
|
throw new Error("TransOne library build requires config.library");
|
|
794
1302
|
}
|
|
795
|
-
await
|
|
796
|
-
await
|
|
1303
|
+
await rm3(library.outDir, { recursive: true, force: true });
|
|
1304
|
+
await mkdir3(library.outDir, { recursive: true });
|
|
797
1305
|
if (library.dts) {
|
|
798
1306
|
for (const tsconfig of library.tsconfigs) {
|
|
799
1307
|
await runTsc(config.root, tsconfig);
|
|
@@ -803,7 +1311,7 @@ async function buildLibrary(config) {
|
|
|
803
1311
|
const result = await Bun.build({
|
|
804
1312
|
entrypoints: [library.entry],
|
|
805
1313
|
outdir: library.outDir,
|
|
806
|
-
root:
|
|
1314
|
+
root: dirname4(library.entry),
|
|
807
1315
|
target: "browser",
|
|
808
1316
|
format: "esm",
|
|
809
1317
|
sourcemap: library.sourcemap ? "linked" : undefined,
|
|
@@ -817,7 +1325,7 @@ async function buildLibrary(config) {
|
|
|
817
1325
|
${result.logs.map((log) => log.message).join(`
|
|
818
1326
|
`)}`);
|
|
819
1327
|
}
|
|
820
|
-
const assetsBuilt = result.outputs.map((output) =>
|
|
1328
|
+
const assetsBuilt = result.outputs.map((output) => resolve5(output.path));
|
|
821
1329
|
return { root: config.root, outDir: library.outDir, assetsBuilt };
|
|
822
1330
|
}
|
|
823
1331
|
async function runTsc(root, tsconfig) {
|
|
@@ -833,23 +1341,23 @@ async function runTsc(root, tsconfig) {
|
|
|
833
1341
|
}
|
|
834
1342
|
|
|
835
1343
|
// src/create.ts
|
|
836
|
-
import { existsSync as
|
|
837
|
-
import { basename, join } from "path";
|
|
1344
|
+
import { existsSync as existsSync4, mkdirSync, writeFileSync } from "fs";
|
|
1345
|
+
import { basename as basename2, join as join2 } from "path";
|
|
838
1346
|
var TRANSONE_FRAMEWORK_VERSION = "0.4.0";
|
|
839
|
-
var TRANSONE_CLI_VERSION = "0.
|
|
1347
|
+
var TRANSONE_CLI_VERSION = "0.5.0";
|
|
840
1348
|
var GITHUB_URL = "https://github.com/geektech-team/transone";
|
|
841
1349
|
function createProject(options = {}) {
|
|
842
1350
|
const root = options.root ?? process.cwd();
|
|
843
|
-
const name = options.name ??
|
|
1351
|
+
const name = options.name ?? basename2(root);
|
|
844
1352
|
const files = scaffoldFiles(name);
|
|
845
|
-
const existing = files.filter((file) =>
|
|
1353
|
+
const existing = files.filter((file) => existsSync4(join2(root, file.path)));
|
|
846
1354
|
if (existing.length > 0) {
|
|
847
1355
|
throw new Error(`Refusing to overwrite existing TransOne project files: ${existing.map((file) => file.path).join(", ")}`);
|
|
848
1356
|
}
|
|
849
|
-
mkdirSync(
|
|
1357
|
+
mkdirSync(join2(root, "src"), { recursive: true });
|
|
850
1358
|
const created = [];
|
|
851
1359
|
for (const file of files) {
|
|
852
|
-
writeFileSync(
|
|
1360
|
+
writeFileSync(join2(root, file.path), file.content, "utf8");
|
|
853
1361
|
created.push(file.path);
|
|
854
1362
|
}
|
|
855
1363
|
return { root, files: created };
|
|
@@ -991,11 +1499,11 @@ app.mount();
|
|
|
991
1499
|
// src/server.ts
|
|
992
1500
|
import { randomUUID } from "crypto";
|
|
993
1501
|
import {
|
|
994
|
-
basename as
|
|
1502
|
+
basename as basename3,
|
|
995
1503
|
extname,
|
|
996
1504
|
isAbsolute as isAbsolute4,
|
|
997
1505
|
relative as relative4,
|
|
998
|
-
resolve as
|
|
1506
|
+
resolve as resolve6,
|
|
999
1507
|
sep as sep3
|
|
1000
1508
|
} from "path";
|
|
1001
1509
|
|
|
@@ -1084,7 +1592,7 @@ function filterHeaders(source) {
|
|
|
1084
1592
|
// src/watch.ts
|
|
1085
1593
|
import { watch } from "fs";
|
|
1086
1594
|
import { readdir, stat } from "fs/promises";
|
|
1087
|
-
import { isAbsolute as isAbsolute3, join as
|
|
1595
|
+
import { isAbsolute as isAbsolute3, join as join3, relative as relative3 } from "path";
|
|
1088
1596
|
var RECURSIVE_WATCH_UNSUPPORTED_ERROR = "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM";
|
|
1089
1597
|
var DEFAULT_DEBOUNCE_MS = 100;
|
|
1090
1598
|
var DEFAULT_POLL_INTERVAL_MS = 300;
|
|
@@ -1195,7 +1703,7 @@ async function collectRelevantFiles(root, isRelevant, output) {
|
|
|
1195
1703
|
if (relativeDirectory === undefined) {
|
|
1196
1704
|
break;
|
|
1197
1705
|
}
|
|
1198
|
-
const absoluteDirectory =
|
|
1706
|
+
const absoluteDirectory = join3(root, relativeDirectory);
|
|
1199
1707
|
let entries;
|
|
1200
1708
|
try {
|
|
1201
1709
|
entries = await readdir(absoluteDirectory, { withFileTypes: true });
|
|
@@ -1212,7 +1720,7 @@ async function collectRelevantFiles(root, isRelevant, output) {
|
|
|
1212
1720
|
continue;
|
|
1213
1721
|
}
|
|
1214
1722
|
try {
|
|
1215
|
-
const info = await stat(
|
|
1723
|
+
const info = await stat(join3(root, relativePath));
|
|
1216
1724
|
output.set(relativePath, { mtimeMs: info.mtimeMs, size: info.size });
|
|
1217
1725
|
} catch {}
|
|
1218
1726
|
}
|
|
@@ -1311,11 +1819,11 @@ async function createServerInstance(options, watch2) {
|
|
|
1311
1819
|
for (const [route, entry] of Object.entries(config.pages)) {
|
|
1312
1820
|
await renderProjectHtml(config, {}, entry, route);
|
|
1313
1821
|
}
|
|
1314
|
-
const developmentOutDir =
|
|
1822
|
+
const developmentOutDir = resolve6(config.root, "dist", "dev", "h5");
|
|
1315
1823
|
await assertSafeSubdirectory(config.root, developmentOutDir, INVALID_DEVELOPMENT_DIRECTORY_MESSAGE);
|
|
1316
1824
|
const proxy = createProxyHandler(config.server.proxy);
|
|
1317
1825
|
const sessionId = createGenerationId();
|
|
1318
|
-
const sessionOutDir =
|
|
1826
|
+
const sessionOutDir = resolve6(developmentOutDir, sessionId);
|
|
1319
1827
|
const artifacts = new Map;
|
|
1320
1828
|
const buildProject = createDevelopmentBuilder(sessionId, sessionOutDir);
|
|
1321
1829
|
const liveReload = watch2 ? createLiveReloadHub() : undefined;
|
|
@@ -1550,11 +2058,11 @@ function isWatchedFile(instance, relativePath) {
|
|
|
1550
2058
|
if (segments.some((segment) => IGNORED_WATCH_SEGMENTS.has(segment))) {
|
|
1551
2059
|
return false;
|
|
1552
2060
|
}
|
|
1553
|
-
const absolutePath =
|
|
2061
|
+
const absolutePath = resolve6(instance.config.root, relativePath);
|
|
1554
2062
|
if (isWithinOrEqual(instance.config.build.outDir, absolutePath)) {
|
|
1555
2063
|
return false;
|
|
1556
2064
|
}
|
|
1557
|
-
const base =
|
|
2065
|
+
const base = basename3(absolutePath);
|
|
1558
2066
|
if (base.startsWith(".") && absolutePath !== instance.config.configFile) {
|
|
1559
2067
|
return false;
|
|
1560
2068
|
}
|
|
@@ -1581,7 +2089,7 @@ function createDevelopmentBuilder(sessionId, sessionOutDir) {
|
|
|
1581
2089
|
}
|
|
1582
2090
|
async function buildProjectBundle(entry, sessionId, sessionOutDir) {
|
|
1583
2091
|
const generationId = createGenerationId();
|
|
1584
|
-
const generationOutDir =
|
|
2092
|
+
const generationOutDir = resolve6(sessionOutDir, generationId);
|
|
1585
2093
|
const generationUrl = `${DEVELOPMENT_URL_PREFIX}/${sessionId}/${generationId}`;
|
|
1586
2094
|
const buildOptions = {
|
|
1587
2095
|
entrypoints: [entry],
|
|
@@ -1645,7 +2153,7 @@ function publishDevelopmentBundle(bundle, artifacts) {
|
|
|
1645
2153
|
}
|
|
1646
2154
|
}
|
|
1647
2155
|
function createDevelopmentOutput(generationOutDir, generationUrl, output) {
|
|
1648
|
-
const filePath =
|
|
2156
|
+
const filePath = resolve6(output.path);
|
|
1649
2157
|
const pathFromGeneration = relative4(generationOutDir, filePath);
|
|
1650
2158
|
if (pathFromGeneration === "" || pathFromGeneration === ".." || pathFromGeneration.startsWith(`..${sep3}`) || isAbsolute4(pathFromGeneration)) {
|
|
1651
2159
|
throw new Error(`Development output must not escape outside its generation directory: ${output.path}`);
|
|
@@ -1667,7 +2175,7 @@ function buildFailureResponse() {
|
|
|
1667
2175
|
});
|
|
1668
2176
|
}
|
|
1669
2177
|
|
|
1670
|
-
export { TARGET_TYPES, isTargetType, MP_TARGET_TYPES, isMpTargetType, defineConfig, resolveConfig, WebTarget, MpTarget, mpWeixinTarget, mpAlipayTarget, mpBytedanceTarget,
|
|
2178
|
+
export { TARGET_TYPES, isTargetType, MP_TARGET_TYPES, isMpTargetType, defineConfig, resolveConfig, WebTarget, MpTarget, mpWeixinTarget, mpAlipayTarget, mpBytedanceTarget, mpXiaohongshuTarget, TargetRegistry, targetRegistry, build, createProject, startDevServer };
|
|
1671
2179
|
|
|
1672
|
-
//# debugId=
|
|
1673
|
-
//# sourceMappingURL=index-
|
|
2180
|
+
//# debugId=53ACD0D6DD0AC45964756E2164756E21
|
|
2181
|
+
//# sourceMappingURL=index-nag8rsrg.js.map
|