@weapp-tailwindcss/env 0.1.0 → 0.2.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 +28 -6
- package/README.zh-CN.md +28 -6
- package/dist/index.cjs +479 -83
- package/dist/index.d.cts +35 -3
- package/dist/index.d.ts +35 -3
- package/dist/index.js +476 -84
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -37,22 +37,74 @@ function isRunningInHBuilderX(options = {}) {
|
|
|
37
37
|
return matchesHBuilderXPluginCwd(options.cwd ?? process.cwd());
|
|
38
38
|
}
|
|
39
39
|
//#endregion
|
|
40
|
+
//#region src/matching.ts
|
|
41
|
+
function evidence(source, key, value, file) {
|
|
42
|
+
return {
|
|
43
|
+
source,
|
|
44
|
+
key,
|
|
45
|
+
...value !== void 0 ? { value } : {},
|
|
46
|
+
...file !== void 0 ? { path: file } : {}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function collectMatches(matches, all) {
|
|
50
|
+
const result = [];
|
|
51
|
+
for (const candidate of matches) {
|
|
52
|
+
result.push(candidate);
|
|
53
|
+
if (!all) break;
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
function detectionReport(candidates) {
|
|
58
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
59
|
+
for (const candidate of candidates) {
|
|
60
|
+
const existing = grouped.get(candidate.appType);
|
|
61
|
+
if (existing) existing.evidence.push(...candidate.evidence);
|
|
62
|
+
else grouped.set(candidate.appType, {
|
|
63
|
+
...candidate,
|
|
64
|
+
evidence: [...candidate.evidence]
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const unique = [...grouped.values()];
|
|
68
|
+
const appType = unique[0]?.appType;
|
|
69
|
+
const family = (value) => value.startsWith("uni-app") ? "uni-app" : value;
|
|
70
|
+
return {
|
|
71
|
+
appType,
|
|
72
|
+
candidates: unique,
|
|
73
|
+
conflicts: appType === void 0 ? [] : unique.filter((candidate) => family(candidate.appType) !== family(appType)).map((candidate) => candidate.appType)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
40
77
|
//#region src/platform.ts
|
|
41
|
-
const
|
|
42
|
-
"alipay",
|
|
43
|
-
"
|
|
44
|
-
"jd",
|
|
45
|
-
"qq",
|
|
46
|
-
"swan",
|
|
47
|
-
"tt",
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
78
|
+
const MPX_TO_UNI_PLATFORM = /* @__PURE__ */ new Map([
|
|
79
|
+
["ali", "mp-alipay"],
|
|
80
|
+
["dd", "mp-dingtalk"],
|
|
81
|
+
["jd", "mp-jd"],
|
|
82
|
+
["qq", "mp-qq"],
|
|
83
|
+
["swan", "mp-baidu"],
|
|
84
|
+
["tt", "mp-toutiao"],
|
|
85
|
+
["wx", "mp-weixin"]
|
|
86
|
+
]);
|
|
87
|
+
const MINI_PROGRAM_PLATFORMS = new Map([
|
|
88
|
+
...[...MPX_TO_UNI_PLATFORM].filter(([alias]) => alias !== "ali" && alias !== "dd"),
|
|
89
|
+
["alipay", "mp-alipay"],
|
|
90
|
+
["baidu", "mp-baidu"],
|
|
91
|
+
["weapp", "mp-weixin"],
|
|
92
|
+
["wechat", "mp-weixin"]
|
|
93
|
+
]);
|
|
94
|
+
const CANONICAL_PLATFORMS = new Map([
|
|
95
|
+
...[...MPX_TO_UNI_PLATFORM.values()].map((value) => [value, value]),
|
|
96
|
+
["web", "web"],
|
|
97
|
+
["h5", "web"],
|
|
98
|
+
["app", "app"],
|
|
99
|
+
["app-plus", "app-plus"],
|
|
100
|
+
["app-android", "app-android"],
|
|
101
|
+
["app-ios", "app-ios"],
|
|
102
|
+
["app-harmony", "app-harmony"]
|
|
51
103
|
]);
|
|
52
104
|
function normalizePlatform(value) {
|
|
53
105
|
return value?.trim().toLowerCase() || void 0;
|
|
54
106
|
}
|
|
55
|
-
function resolvePlatformInfo(value) {
|
|
107
|
+
function resolvePlatformInfo(value, appType) {
|
|
56
108
|
const normalized = normalizePlatform(value);
|
|
57
109
|
const isAppAndroid = normalized === "app-android";
|
|
58
110
|
const isAppIos = normalized === "app-ios";
|
|
@@ -64,7 +116,7 @@ function resolvePlatformInfo(value) {
|
|
|
64
116
|
isAppAndroid,
|
|
65
117
|
isAppHarmony,
|
|
66
118
|
isAppIos,
|
|
67
|
-
isMp: normalized?.startsWith("mp-") === true || (normalized ? MINI_PROGRAM_PLATFORMS.has(normalized) : false),
|
|
119
|
+
isMp: normalized?.startsWith("mp-") === true || (normalized ? MINI_PROGRAM_PLATFORMS.has(normalized) || appType === "mpx" && MPX_TO_UNI_PLATFORM.has(normalized) : false),
|
|
68
120
|
isWeb: normalized?.startsWith("web") === true || normalized === "h5"
|
|
69
121
|
};
|
|
70
122
|
}
|
|
@@ -74,11 +126,19 @@ function resolvePlatform(value) {
|
|
|
74
126
|
function resolveTaroPlatform(value = getProcessEnv().TARO_ENV) {
|
|
75
127
|
return resolvePlatform(value);
|
|
76
128
|
}
|
|
129
|
+
/** 读取 Taro 环境快照;省略快照时才使用调用时的进程环境。 */
|
|
130
|
+
function resolveTaroPlatformFromEnv(env = getProcessEnv()) {
|
|
131
|
+
return resolvePlatform(env.TARO_ENV);
|
|
132
|
+
}
|
|
77
133
|
function resolveMpxPlatformValue(env = getProcessEnv()) {
|
|
78
134
|
return env.MPX_CURRENT_TARGET_MODE ?? env.MPX_CLI_MODE;
|
|
79
135
|
}
|
|
80
136
|
function resolveMpxPlatform(value = resolveMpxPlatformValue()) {
|
|
81
|
-
return
|
|
137
|
+
return resolvePlatformInfo(value, "mpx");
|
|
138
|
+
}
|
|
139
|
+
/** 读取 MPX 环境快照,保留 current mode 的空字符串优先级。 */
|
|
140
|
+
function resolveMpxPlatformFromEnv(env = getProcessEnv()) {
|
|
141
|
+
return resolvePlatformInfo(resolveMpxPlatformValue(env), "mpx");
|
|
82
142
|
}
|
|
83
143
|
function resolveUniPlatform(value = getProcessEnv().UNI_PLATFORM) {
|
|
84
144
|
return resolvePlatform(value);
|
|
@@ -96,136 +156,468 @@ function resolveUniPlatformsFromEnv(env = getProcessEnv()) {
|
|
|
96
156
|
uniUtsPlatform: resolvePlatform(env.UNI_UTS_PLATFORM)
|
|
97
157
|
};
|
|
98
158
|
}
|
|
99
|
-
const MPX_TO_UNI_PLATFORM = {
|
|
100
|
-
ali: "mp-alipay",
|
|
101
|
-
dd: "mp-dingtalk",
|
|
102
|
-
jd: "mp-jd",
|
|
103
|
-
qq: "mp-qq",
|
|
104
|
-
swan: "mp-baidu",
|
|
105
|
-
tt: "mp-toutiao",
|
|
106
|
-
wx: "mp-weixin"
|
|
107
|
-
};
|
|
108
159
|
function normalizeFrameworkStylePlatform(platform, appType) {
|
|
109
160
|
const normalized = platform?.trim().toLowerCase();
|
|
110
161
|
if (!normalized) return;
|
|
111
|
-
if (appType === "mpx") return MPX_TO_UNI_PLATFORM
|
|
162
|
+
if (appType === "mpx") return MPX_TO_UNI_PLATFORM.get(normalized) ?? normalized;
|
|
112
163
|
return normalized;
|
|
113
164
|
}
|
|
165
|
+
function resolvePlatformIdentity(platform, appType) {
|
|
166
|
+
const normalized = normalizePlatform(platform);
|
|
167
|
+
return {
|
|
168
|
+
raw: platform,
|
|
169
|
+
normalized,
|
|
170
|
+
canonical: normalized ? (appType === "mpx" ? MPX_TO_UNI_PLATFORM.get(normalized) : void 0) ?? MINI_PROGRAM_PLATFORMS.get(normalized) ?? CANONICAL_PLATFORMS.get(normalized) : void 0
|
|
171
|
+
};
|
|
172
|
+
}
|
|
114
173
|
//#endregion
|
|
115
174
|
//#region src/detect-env.ts
|
|
116
|
-
function
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
175
|
+
function* matchEnvironment(env, options = {}) {
|
|
176
|
+
for (const key of ["WEAPP_TW_TARGET", "WEAPP_TAILWINDCSS_TARGET"]) {
|
|
177
|
+
const value = env[key];
|
|
178
|
+
if (value === "weapp-vite") yield {
|
|
179
|
+
appType: "weapp-vite",
|
|
180
|
+
evidence: [evidence("env", key, value)]
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const taro = env.TARO_ENV;
|
|
184
|
+
if (taro) yield {
|
|
185
|
+
appType: "taro",
|
|
186
|
+
evidence: [evidence("env", "TARO_ENV", taro)]
|
|
187
|
+
};
|
|
188
|
+
for (const key of ["MPX_CLI_MODE", "MPX_CURRENT_TARGET_MODE"]) {
|
|
189
|
+
const value = env[key];
|
|
190
|
+
if (value) yield {
|
|
191
|
+
appType: "mpx",
|
|
192
|
+
evidence: [evidence("env", key, value)]
|
|
193
|
+
};
|
|
194
|
+
}
|
|
120
195
|
const { uniPlatform, uniUtsPlatform } = resolveUniPlatformsFromEnv(env);
|
|
121
|
-
if (uniUtsPlatform.normalized)
|
|
122
|
-
|
|
196
|
+
if (uniUtsPlatform.normalized) yield {
|
|
197
|
+
appType: "uni-app-x",
|
|
198
|
+
evidence: [evidence("env", "UNI_UTS_PLATFORM", uniUtsPlatform.raw)]
|
|
199
|
+
};
|
|
200
|
+
if (uniPlatform.normalized) yield {
|
|
201
|
+
appType: "uni-app-vite",
|
|
202
|
+
evidence: [evidence("env", "UNI_PLATFORM", uniPlatform.raw)]
|
|
203
|
+
};
|
|
123
204
|
if (isRunningInHBuilderX({
|
|
124
205
|
cwd: options.cwd,
|
|
125
206
|
env
|
|
126
|
-
}))
|
|
207
|
+
})) yield {
|
|
208
|
+
appType: options.hbuilderxVite === false ? "uni-app" : "uni-app-vite",
|
|
209
|
+
evidence: [evidence("hbuilderx", "cwd", options.cwd ?? process.cwd())]
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function detectAppTypeFromEnv(env = getProcessEnv(), options = {}) {
|
|
213
|
+
return collectMatches(matchEnvironment(env, options), false)[0]?.appType;
|
|
214
|
+
}
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/script-command.ts
|
|
217
|
+
const ASSIGNMENT_RE = /^[A-Z_]\w*=/iu;
|
|
218
|
+
const COMMAND_TYPES = /* @__PURE__ */ new Map([
|
|
219
|
+
["mpx", "mpx"],
|
|
220
|
+
["mpx-cli-service", "mpx"],
|
|
221
|
+
["taro", "taro"],
|
|
222
|
+
["uni", "uni-app-vite"],
|
|
223
|
+
["weapp-vite", "weapp-vite"]
|
|
224
|
+
]);
|
|
225
|
+
const PNPM_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
226
|
+
"-C",
|
|
227
|
+
"--dir",
|
|
228
|
+
"-F",
|
|
229
|
+
"--filter",
|
|
230
|
+
"--filter-prod",
|
|
231
|
+
"--reporter"
|
|
232
|
+
]);
|
|
233
|
+
const PNPM_FLAGS = /* @__PURE__ */ new Set([
|
|
234
|
+
"-w",
|
|
235
|
+
"--workspace-root",
|
|
236
|
+
"-r",
|
|
237
|
+
"--recursive",
|
|
238
|
+
"-s",
|
|
239
|
+
"--silent"
|
|
240
|
+
]);
|
|
241
|
+
const NPX_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
242
|
+
"-p",
|
|
243
|
+
"--package",
|
|
244
|
+
"--cache",
|
|
245
|
+
"--userconfig"
|
|
246
|
+
]);
|
|
247
|
+
const NPX_FLAGS = /* @__PURE__ */ new Set([
|
|
248
|
+
"-y",
|
|
249
|
+
"--yes",
|
|
250
|
+
"--no",
|
|
251
|
+
"--no-install",
|
|
252
|
+
"-q",
|
|
253
|
+
"--quiet"
|
|
254
|
+
]);
|
|
255
|
+
const ENV_VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
256
|
+
"-u",
|
|
257
|
+
"--unset",
|
|
258
|
+
"-C",
|
|
259
|
+
"--chdir"
|
|
260
|
+
]);
|
|
261
|
+
function readExpansionEnd(script, start, opening, closing) {
|
|
262
|
+
let depth = 1;
|
|
263
|
+
let quote;
|
|
264
|
+
for (let index = start + 2; index < script.length; index++) {
|
|
265
|
+
const character = script[index];
|
|
266
|
+
if (character === "\\" && quote !== "'") index++;
|
|
267
|
+
else if (quote) {
|
|
268
|
+
if (character === quote) quote = void 0;
|
|
269
|
+
} else if (character === "\"" || character === "'" || character === "`") quote = character;
|
|
270
|
+
else if (character === opening) depth++;
|
|
271
|
+
else if (character === closing && --depth === 0) return index;
|
|
272
|
+
}
|
|
273
|
+
return -1;
|
|
274
|
+
}
|
|
275
|
+
function tokenizeCommands(script) {
|
|
276
|
+
const commands = [];
|
|
277
|
+
let command = [];
|
|
278
|
+
let value = "";
|
|
279
|
+
let active = false;
|
|
280
|
+
let quoted = false;
|
|
281
|
+
let shellAssignment = false;
|
|
282
|
+
let protectedPrefix = false;
|
|
283
|
+
let quote;
|
|
284
|
+
function flushToken() {
|
|
285
|
+
if (active) {
|
|
286
|
+
command.push({
|
|
287
|
+
value,
|
|
288
|
+
quoted,
|
|
289
|
+
shellAssignment
|
|
290
|
+
});
|
|
291
|
+
value = "";
|
|
292
|
+
active = false;
|
|
293
|
+
quoted = false;
|
|
294
|
+
shellAssignment = false;
|
|
295
|
+
protectedPrefix = false;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function flushCommand() {
|
|
299
|
+
flushToken();
|
|
300
|
+
if (command.length) {
|
|
301
|
+
commands.push(command);
|
|
302
|
+
command = [];
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
for (let index = 0; index < script.length; index++) {
|
|
306
|
+
const character = script[index];
|
|
307
|
+
const next = script[index + 1];
|
|
308
|
+
if (character === "\\" && quote !== "'" && next && /[\s"'\\$`;&|]/u.test(next) || character === "^" && !quote && next && /[\s"^;&|]/u.test(next)) {
|
|
309
|
+
if (next !== "\n" && next !== "\r") {
|
|
310
|
+
protectedPrefix = true;
|
|
311
|
+
value += next;
|
|
312
|
+
active = true;
|
|
313
|
+
} else if (next === "\r" && script[index + 2] === "\n") index++;
|
|
314
|
+
index++;
|
|
315
|
+
} else if (character === "$" && (next === "(" || next === "{") && quote !== "'") {
|
|
316
|
+
const end = readExpansionEnd(script, index, next, next === "(" ? ")" : "}");
|
|
317
|
+
if (end === -1) return [];
|
|
318
|
+
value += script.slice(index, end + 1);
|
|
319
|
+
protectedPrefix = true;
|
|
320
|
+
active = true;
|
|
321
|
+
index = end;
|
|
322
|
+
} else if (quote) {
|
|
323
|
+
if (character === quote) quote = void 0;
|
|
324
|
+
else value += character;
|
|
325
|
+
} else if (character === "\"" || character === "'" || character === "`") {
|
|
326
|
+
quote = character;
|
|
327
|
+
quoted = true;
|
|
328
|
+
protectedPrefix = true;
|
|
329
|
+
active = true;
|
|
330
|
+
if (character === "`") value += character;
|
|
331
|
+
} else if (character === "<" && next === "<") return [];
|
|
332
|
+
else if ((character === ">" || character === "<") && next === "&" || character === "&" && next === ">") {
|
|
333
|
+
value += character + next;
|
|
334
|
+
active = true;
|
|
335
|
+
index++;
|
|
336
|
+
} else if (character === "#" && !active) while (script[index + 1] && script[index + 1] !== "\n") index++;
|
|
337
|
+
else if (character === ";" || character === "&" || character === "|" || character === "\n" || character === "\r") flushCommand();
|
|
338
|
+
else if (/\s/u.test(character)) flushToken();
|
|
339
|
+
else {
|
|
340
|
+
if (character === "=" && !protectedPrefix && ASSIGNMENT_RE.test(`${value}=`)) shellAssignment = true;
|
|
341
|
+
value += character;
|
|
342
|
+
active = true;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (quote) return [];
|
|
346
|
+
flushCommand();
|
|
347
|
+
return commands;
|
|
348
|
+
}
|
|
349
|
+
function executableName(value, allowVersion = false) {
|
|
350
|
+
if (allowVersion && value.startsWith("@")) return value;
|
|
351
|
+
const name = path.win32.basename(path.posix.basename(value));
|
|
352
|
+
const executable = /\.(?:cmd|bat|exe)$/iu.test(name) ? name.replace(/\.(?:cmd|bat|exe)$/iu, "").toLowerCase() : name;
|
|
353
|
+
return allowVersion ? executable.replace(/@[^@]+$/u, "") : executable;
|
|
354
|
+
}
|
|
355
|
+
function skipAssignments(tokens, index, shellPosition = false) {
|
|
356
|
+
while (tokens[index] && (shellPosition ? tokens[index].shellAssignment : ASSIGNMENT_RE.test(tokens[index].value))) index++;
|
|
357
|
+
return index;
|
|
358
|
+
}
|
|
359
|
+
function skipOptions(tokens, index, flags, valueOptions) {
|
|
360
|
+
while (tokens[index]?.value.startsWith("-")) {
|
|
361
|
+
const value = tokens[index].value;
|
|
362
|
+
if (value === "--") return index + 1;
|
|
363
|
+
if (flags.has(value)) index++;
|
|
364
|
+
else if (valueOptions.has(value)) {
|
|
365
|
+
if (!tokens[index + 1]) return tokens.length;
|
|
366
|
+
index += 2;
|
|
367
|
+
} else if (value.includes("=") && valueOptions.has(value.slice(0, value.indexOf("=")))) index++;
|
|
368
|
+
else return tokens.length;
|
|
369
|
+
}
|
|
370
|
+
return index;
|
|
371
|
+
}
|
|
372
|
+
function collectCommands(script, detected, depth = 0) {
|
|
373
|
+
if (depth > 8) return;
|
|
374
|
+
for (const tokens of tokenizeCommands(script)) {
|
|
375
|
+
let index = skipAssignments(tokens, 0, true);
|
|
376
|
+
let allowVersion = false;
|
|
377
|
+
while (tokens[index]) {
|
|
378
|
+
const name = executableName(tokens[index].value, allowVersion);
|
|
379
|
+
const appType = COMMAND_TYPES.get(name);
|
|
380
|
+
if (appType) {
|
|
381
|
+
detected.add(appType);
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
allowVersion = false;
|
|
385
|
+
index++;
|
|
386
|
+
if (name === "cross-env" || name === "cross-env-shell") {
|
|
387
|
+
index = skipAssignments(tokens, index);
|
|
388
|
+
const payload = tokens[index];
|
|
389
|
+
if (name === "cross-env-shell" && payload?.quoted) {
|
|
390
|
+
collectCommands(payload.value, detected, depth + 1);
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
} else if (name === "env") {
|
|
394
|
+
index = skipOptions(tokens, index, /* @__PURE__ */ new Set(["-i", "--ignore-environment"]), ENV_VALUE_OPTIONS);
|
|
395
|
+
index = skipAssignments(tokens, index);
|
|
396
|
+
} else if (name === "pnpm") {
|
|
397
|
+
index = skipOptions(tokens, index, PNPM_FLAGS, PNPM_VALUE_OPTIONS);
|
|
398
|
+
if (tokens[index]?.value === "exec" || tokens[index]?.value === "dlx") {
|
|
399
|
+
const dlx = tokens[index].value === "dlx";
|
|
400
|
+
index++;
|
|
401
|
+
index = skipOptions(tokens, index, dlx ? NPX_FLAGS : PNPM_FLAGS, dlx ? NPX_VALUE_OPTIONS : PNPM_VALUE_OPTIONS);
|
|
402
|
+
allowVersion = dlx;
|
|
403
|
+
}
|
|
404
|
+
} else if (name === "npx") {
|
|
405
|
+
index = skipOptions(tokens, index, NPX_FLAGS, NPX_VALUE_OPTIONS);
|
|
406
|
+
allowVersion = true;
|
|
407
|
+
} else break;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* 仅识别脚本中明确的命令位置,不执行脚本或推断任意参数中的框架名称。
|
|
413
|
+
*/
|
|
414
|
+
function detectFrameworkCommands(script) {
|
|
415
|
+
const detected = /* @__PURE__ */ new Set();
|
|
416
|
+
collectCommands(script, detected);
|
|
417
|
+
return [...detected];
|
|
127
418
|
}
|
|
128
419
|
//#endregion
|
|
129
420
|
//#region src/package.ts
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
421
|
+
const FRAMEWORK_PRIORITY = [
|
|
422
|
+
"weapp-vite",
|
|
423
|
+
"mpx",
|
|
424
|
+
"taro",
|
|
425
|
+
"uni-app-x",
|
|
426
|
+
"uni-app-vite",
|
|
427
|
+
"uni-app"
|
|
428
|
+
];
|
|
429
|
+
const DEPENDENCY_FIELDS = [
|
|
430
|
+
"dependencies",
|
|
431
|
+
"devDependencies",
|
|
432
|
+
"peerDependencies",
|
|
433
|
+
"optionalDependencies"
|
|
434
|
+
];
|
|
435
|
+
function matchesDependency(appType, name) {
|
|
436
|
+
switch (appType) {
|
|
437
|
+
case "weapp-vite": return name === "weapp-vite" || name.startsWith("@weapp-vite/");
|
|
438
|
+
case "mpx": return name.startsWith("@mpxjs/");
|
|
439
|
+
case "taro": return name.startsWith("@tarojs/");
|
|
440
|
+
case "uni-app-x": return name === "@dcloudio/uni-uts-v1" || name === "@weapp-tailwindcss/debug-uni-app-x";
|
|
441
|
+
case "uni-app-vite": return name === "@dcloudio/vite-plugin-uni";
|
|
442
|
+
case "uni-app": return name === "@dcloudio/vue-cli-plugin-uni" || name === "@dcloudio/uni-app";
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function packageMatcher(pkg, file) {
|
|
446
|
+
let scripts;
|
|
447
|
+
return (appType, all) => {
|
|
448
|
+
const result = [];
|
|
449
|
+
for (const field of DEPENDENCY_FIELDS) for (const [name, version] of Object.entries(pkg[field] ?? {})) if (matchesDependency(appType, name)) {
|
|
450
|
+
result.push(evidence("dependency", `${field}.${name}`, version, file));
|
|
451
|
+
if (!all) return result;
|
|
452
|
+
}
|
|
453
|
+
if (appType === "uni-app" && Object.hasOwn(pkg, "uni-app")) {
|
|
454
|
+
result.push(evidence("package-field", "uni-app", void 0, file));
|
|
455
|
+
if (!all) return result;
|
|
456
|
+
}
|
|
457
|
+
if (appType === "uni-app-x") return result;
|
|
458
|
+
scripts ??= Object.entries(pkg.scripts ?? {}).map(([name, value]) => ({
|
|
459
|
+
name,
|
|
460
|
+
value,
|
|
461
|
+
commands: detectFrameworkCommands(value)
|
|
462
|
+
}));
|
|
463
|
+
for (const script of scripts) {
|
|
464
|
+
const commandType = appType === "uni-app" ? "uni-app-vite" : appType;
|
|
465
|
+
if (script.commands.includes(commandType)) {
|
|
466
|
+
result.push(evidence("script", `scripts.${script.name}`, script.value, file));
|
|
467
|
+
if (!all) return result;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return result;
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
function* matchPackageJson(pkg, all, file) {
|
|
474
|
+
const match = packageMatcher(pkg, file);
|
|
475
|
+
for (const appType of FRAMEWORK_PRIORITY) {
|
|
476
|
+
const evidence = match(appType, all);
|
|
477
|
+
if (evidence.length) yield {
|
|
478
|
+
appType,
|
|
479
|
+
evidence
|
|
480
|
+
};
|
|
481
|
+
}
|
|
148
482
|
}
|
|
149
483
|
function isWeappVitePackage(pkg) {
|
|
150
|
-
|
|
151
|
-
return dependencyNames.has("weapp-vite") || hasDependencyPrefix(dependencyNames, "@weapp-vite/") || hasScriptMatch(pkg, WEAPP_VITE_SCRIPT_RE);
|
|
484
|
+
return packageMatcher(pkg)("weapp-vite", false).length > 0;
|
|
152
485
|
}
|
|
153
486
|
function isMpxPackage(pkg) {
|
|
154
|
-
return
|
|
487
|
+
return packageMatcher(pkg)("mpx", false).length > 0;
|
|
155
488
|
}
|
|
156
489
|
function isTaroPackage(pkg) {
|
|
157
|
-
return
|
|
490
|
+
return packageMatcher(pkg)("taro", false).length > 0;
|
|
158
491
|
}
|
|
159
492
|
function isUniAppVitePackage(pkg) {
|
|
160
|
-
return
|
|
493
|
+
return packageMatcher(pkg)("uni-app-vite", false).length > 0;
|
|
161
494
|
}
|
|
162
495
|
function isUniAppXPackage(pkg) {
|
|
163
|
-
|
|
164
|
-
return dependencyNames.has("@dcloudio/uni-uts-v1") || dependencyNames.has("@weapp-tailwindcss/debug-uni-app-x");
|
|
496
|
+
return packageMatcher(pkg)("uni-app-x", false).length > 0;
|
|
165
497
|
}
|
|
166
498
|
function isUniAppPackage(pkg) {
|
|
167
|
-
|
|
168
|
-
return dependencyNames.has("@dcloudio/vue-cli-plugin-uni") || dependencyNames.has("@dcloudio/uni-app") || Object.hasOwn(pkg, "uni-app") || hasScriptMatch(pkg, UNI_APP_SCRIPT_RE);
|
|
499
|
+
return packageMatcher(pkg)("uni-app", false).length > 0;
|
|
169
500
|
}
|
|
170
501
|
function isUniAppXManifest(manifest) {
|
|
171
502
|
return Boolean(manifest && Object.hasOwn(manifest, "uni-app-x"));
|
|
172
503
|
}
|
|
173
504
|
function detectAppTypeFromPackageJson(pkg) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
505
|
+
return collectMatches(matchPackageJson(pkg, false), false)[0]?.appType;
|
|
506
|
+
}
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region src/manifest.ts
|
|
509
|
+
/** 仅移除字符串外的注释,其余语法仍交给严格 JSON 解析。 */
|
|
510
|
+
function parseManifestJson(source) {
|
|
511
|
+
const characters = source.split("");
|
|
512
|
+
let inString = false;
|
|
513
|
+
for (let index = 0; index < source.length; index++) {
|
|
514
|
+
const character = source[index];
|
|
515
|
+
if (inString) {
|
|
516
|
+
if (character === "\\") index++;
|
|
517
|
+
else if (character === "\"") inString = false;
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
if (character === "\"") {
|
|
521
|
+
inString = true;
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
if (character !== "/") continue;
|
|
525
|
+
if (source[index + 1] === "/") {
|
|
526
|
+
characters[index] = " ";
|
|
527
|
+
characters[++index] = " ";
|
|
528
|
+
while (index + 1 < source.length && source[index + 1] !== "\n" && source[index + 1] !== "\r") characters[++index] = " ";
|
|
529
|
+
} else if (source[index + 1] === "*") {
|
|
530
|
+
characters[index] = " ";
|
|
531
|
+
characters[++index] = " ";
|
|
532
|
+
let closed = false;
|
|
533
|
+
while (++index < source.length) {
|
|
534
|
+
if (source[index] === "*" && source[index + 1] === "/") {
|
|
535
|
+
characters[index] = " ";
|
|
536
|
+
characters[++index] = " ";
|
|
537
|
+
closed = true;
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
if (source[index] !== "\n" && source[index] !== "\r") characters[index] = " ";
|
|
541
|
+
}
|
|
542
|
+
if (!closed) throw new SyntaxError("manifest.json 中存在未闭合的块注释");
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
return JSON.parse(characters.join(""));
|
|
180
546
|
}
|
|
181
547
|
//#endregion
|
|
182
548
|
//#region src/project.ts
|
|
183
549
|
const PACKAGE_JSON_FILE = "package.json";
|
|
184
550
|
const MANIFEST_JSON_FILE = "manifest.json";
|
|
185
551
|
const MPX_MARKERS = [["src", "app.mpx"], ["app.mpx"]];
|
|
186
|
-
function tryReadJson(file) {
|
|
552
|
+
function tryReadJson(file, parse = JSON.parse) {
|
|
187
553
|
if (!existsSync(file)) return;
|
|
188
554
|
try {
|
|
189
|
-
return
|
|
555
|
+
return parse(readFileSync(file, "utf8"));
|
|
190
556
|
} catch {}
|
|
191
557
|
}
|
|
192
|
-
function
|
|
193
|
-
|
|
558
|
+
function manifestMatches(manifest, file) {
|
|
559
|
+
return isUniAppXManifest(manifest) ? [{
|
|
560
|
+
appType: "uni-app-x",
|
|
561
|
+
evidence: [evidence("manifest", "uni-app-x", void 0, file)]
|
|
562
|
+
}] : [];
|
|
194
563
|
}
|
|
195
|
-
function
|
|
564
|
+
function matchRoot(root, searchUp, all) {
|
|
196
565
|
const resolvedRoot = path.resolve(root);
|
|
197
|
-
if (!existsSync(resolvedRoot)) return;
|
|
198
|
-
const
|
|
199
|
-
|
|
566
|
+
if (!existsSync(resolvedRoot)) return [];
|
|
567
|
+
const markers = [];
|
|
568
|
+
for (const segments of MPX_MARKERS) {
|
|
569
|
+
const file = path.join(resolvedRoot, ...segments);
|
|
570
|
+
if (existsSync(file)) {
|
|
571
|
+
markers.push(evidence("marker", "app.mpx", void 0, file));
|
|
572
|
+
if (!all) break;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (markers.length) return [{
|
|
576
|
+
appType: "mpx",
|
|
577
|
+
evidence: markers
|
|
578
|
+
}];
|
|
200
579
|
let current = resolvedRoot;
|
|
201
580
|
while (true) {
|
|
202
|
-
|
|
203
|
-
const
|
|
581
|
+
const manifestFile = path.join(current, MANIFEST_JSON_FILE);
|
|
582
|
+
const manifest = manifestMatches(tryReadJson(manifestFile, parseManifestJson), manifestFile);
|
|
583
|
+
if (manifest.length) return manifest;
|
|
584
|
+
const packageFile = path.join(current, PACKAGE_JSON_FILE);
|
|
585
|
+
const pkg = tryReadJson(packageFile);
|
|
204
586
|
if (pkg) {
|
|
205
|
-
const
|
|
206
|
-
if (
|
|
587
|
+
const candidates = collectMatches(matchPackageJson(pkg, all, packageFile), all);
|
|
588
|
+
if (candidates.length) return candidates;
|
|
207
589
|
}
|
|
208
590
|
if (!searchUp) break;
|
|
209
591
|
const parent = path.dirname(current);
|
|
210
592
|
if (parent === current) break;
|
|
211
593
|
current = parent;
|
|
212
594
|
}
|
|
595
|
+
return [];
|
|
213
596
|
}
|
|
214
|
-
function
|
|
215
|
-
|
|
597
|
+
function matchAppType(options, all) {
|
|
598
|
+
const manifest = manifestMatches(options.manifest);
|
|
599
|
+
if (manifest.length) return manifest;
|
|
216
600
|
if (options.packageJson) {
|
|
217
|
-
const
|
|
218
|
-
if (
|
|
601
|
+
const candidates = collectMatches(matchPackageJson(options.packageJson, all), all);
|
|
602
|
+
if (candidates.length) return candidates;
|
|
219
603
|
}
|
|
220
604
|
if (options.root) {
|
|
221
|
-
const
|
|
222
|
-
if (
|
|
605
|
+
const candidates = matchRoot(options.root, options.searchUp ?? true, all);
|
|
606
|
+
if (candidates.length) return candidates;
|
|
223
607
|
}
|
|
224
608
|
const env = options.env ?? (options.detectEnv ? getProcessEnv() : void 0);
|
|
225
|
-
if (env) return
|
|
609
|
+
if (!env) return [];
|
|
610
|
+
return collectMatches(matchEnvironment(env, {
|
|
226
611
|
cwd: options.cwd ?? options.root ?? (options.detectEnv ? process.cwd() : void 0),
|
|
227
612
|
hbuilderxVite: options.hbuilderxVite
|
|
228
|
-
});
|
|
613
|
+
}), all);
|
|
614
|
+
}
|
|
615
|
+
function detectAppType(options = {}) {
|
|
616
|
+
return matchAppType(options, false)[0]?.appType;
|
|
617
|
+
}
|
|
618
|
+
/** 解释首次命中阶段的框架候选与冲突,不扩大项目搜索范围。 */
|
|
619
|
+
function detectAppTypeReport(options = {}) {
|
|
620
|
+
return detectionReport(matchAppType(options, true));
|
|
229
621
|
}
|
|
230
622
|
//#endregion
|
|
231
|
-
export { detectAppType, detectAppTypeFromEnv, detectAppTypeFromPackageJson, isMpxPackage, isRunningInHBuilderX, isTaroPackage, isUniAppPackage, isUniAppVitePackage, isUniAppXManifest, isUniAppXPackage, isWeappVitePackage, normalizeFrameworkStylePlatform, resolveMpxPlatform, resolvePlatform, resolveTaroPlatform, resolveUniAppXPlatform, resolveUniPlatform, resolveUniPlatformsFromEnv, resolveUniUtsPlatform };
|
|
623
|
+
export { detectAppType, detectAppTypeFromEnv, detectAppTypeFromPackageJson, detectAppTypeReport, isMpxPackage, isRunningInHBuilderX, isTaroPackage, isUniAppPackage, isUniAppVitePackage, isUniAppXManifest, isUniAppXPackage, isWeappVitePackage, normalizeFrameworkStylePlatform, resolveMpxPlatform, resolveMpxPlatformFromEnv, resolvePlatform, resolvePlatformIdentity, resolveTaroPlatform, resolveTaroPlatformFromEnv, resolveUniAppXPlatform, resolveUniPlatform, resolveUniPlatformsFromEnv, resolveUniUtsPlatform };
|