@dimina/compiler 1.0.7 → 1.0.8

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.
@@ -0,0 +1,544 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import process from "node:process";
5
+ function hasCompileInfo(modulePath, list, preList) {
6
+ const mergeList = Array.isArray(preList) ? [...preList, ...list] : list;
7
+ for (const element of mergeList) {
8
+ if (element.path === modulePath) {
9
+ return true;
10
+ }
11
+ }
12
+ return false;
13
+ }
14
+ function getAbsolutePath(workPath, pagePath, src) {
15
+ if (src.startsWith("/")) {
16
+ return path.join(workPath, src);
17
+ }
18
+ if (pagePath.includes("/miniprogram_npm/")) {
19
+ const componentDir = pagePath.split("/").slice(0, -1).join("/");
20
+ const componentFullPath = workPath + componentDir;
21
+ return path.resolve(componentFullPath, src);
22
+ }
23
+ const relativePath = pagePath.split("/").filter((part) => part !== "").slice(0, -1).join("/");
24
+ return path.resolve(workPath, relativePath, src);
25
+ }
26
+ const assetsMap = {};
27
+ function collectAssets(workPath, pagePath, src, targetPath, appId) {
28
+ if (src.startsWith("http") || src.startsWith("//")) {
29
+ return src;
30
+ }
31
+ if (!/\.(?:png|jpe?g|gif|svg)(?:\?.*)?$/.test(src)) {
32
+ return src;
33
+ }
34
+ const relativePath = pagePath.split("/").slice(0, -1).join("/");
35
+ const absolutePath = src.startsWith("/") ? workPath + src : path.resolve(workPath, relativePath, src);
36
+ if (assetsMap[absolutePath]) {
37
+ return assetsMap[absolutePath];
38
+ }
39
+ try {
40
+ const ext = `.${src.split(".").pop()}`;
41
+ const dirPath = absolutePath.split(path.sep).slice(0, -1).join("/");
42
+ const prefix = uuid();
43
+ const targetStatic = `${targetPath}/main/static`;
44
+ if (!fs.existsSync(targetStatic)) {
45
+ fs.mkdirSync(targetStatic, { recursive: true });
46
+ }
47
+ getFilesWithExtension(dirPath, ext).forEach((file) => {
48
+ fs.copyFileSync(path.resolve(dirPath, file), `${targetStatic}/${prefix}_${file}`);
49
+ });
50
+ const filename = src.split("/").pop();
51
+ const pathPrefix = process.env.ASSETS_PATH_PREFIX ? "" : "/";
52
+ assetsMap[absolutePath] = `${pathPrefix}${appId}/main/static/${prefix}_${filename}`;
53
+ } catch (error) {
54
+ console.log(error);
55
+ }
56
+ return assetsMap[absolutePath] || src;
57
+ }
58
+ function getFilesWithExtension(directory, extension) {
59
+ const files = fs.readdirSync(directory);
60
+ const filteredFiles = files.filter((file) => path.extname(file) === extension);
61
+ return filteredFiles;
62
+ }
63
+ function isObjectEmpty(objectName) {
64
+ if (!objectName) {
65
+ return true;
66
+ }
67
+ return Object.keys(objectName).length === 0 && objectName.constructor === Object;
68
+ }
69
+ function isString(o) {
70
+ return Object.prototype.toString.call(o) === "[object String]";
71
+ }
72
+ function transformRpx(styleText) {
73
+ if (!isString(styleText)) {
74
+ return styleText;
75
+ }
76
+ return styleText.replace(/([+-]?\d+(?:\.\d+)?)rpx/g, (_, pixel) => {
77
+ return `${Number(pixel)}rem`;
78
+ });
79
+ }
80
+ function uuid() {
81
+ return Math.random().toString(36).slice(2, 7);
82
+ }
83
+ const tagWhiteList = [
84
+ "page",
85
+ "wrapper",
86
+ "block",
87
+ "button",
88
+ "camera",
89
+ "checkbox-group",
90
+ "checkbox",
91
+ "cover-image",
92
+ "cover-view",
93
+ "form",
94
+ "icon",
95
+ "image",
96
+ "input",
97
+ "keyboard-accessory",
98
+ "label",
99
+ "map",
100
+ "movable-area",
101
+ "movable-view",
102
+ "navigation-bar",
103
+ "navigator",
104
+ "open-data",
105
+ "page-meta",
106
+ "picker-view-column",
107
+ "picker-view",
108
+ "picker",
109
+ "progress",
110
+ "radio-group",
111
+ "radio",
112
+ "rich-text",
113
+ "root-portal",
114
+ "scroll-view",
115
+ "slider",
116
+ "swiper-item",
117
+ "swiper",
118
+ "switch",
119
+ "template",
120
+ "text",
121
+ "textarea",
122
+ "video",
123
+ "view",
124
+ "web-view"
125
+ ];
126
+ class NpmResolver {
127
+ constructor(workPath) {
128
+ this.workPath = workPath;
129
+ this.miniprogramNpmCache = /* @__PURE__ */ new Map();
130
+ this.packageCache = /* @__PURE__ */ new Map();
131
+ }
132
+ /**
133
+ * 解析组件路径,支持 npm 包组件
134
+ * @param {string} componentPath 组件路径
135
+ * @param {string} pageFilePath 页面文件路径
136
+ * @returns {string} 解析后的组件路径
137
+ */
138
+ resolveComponentPath(componentPath, pageFilePath) {
139
+ if (componentPath.startsWith("./") || componentPath.startsWith("../") || componentPath.startsWith("/")) {
140
+ return this.resolveRelativePath(componentPath, pageFilePath);
141
+ }
142
+ const npmPath = this.resolveNpmComponent(componentPath, pageFilePath);
143
+ if (npmPath) {
144
+ return npmPath;
145
+ }
146
+ return this.resolveRelativePath(componentPath, pageFilePath);
147
+ }
148
+ /**
149
+ * 解析相对路径组件
150
+ * @param {string} componentPath 组件路径
151
+ * @param {string} pageFilePath 页面文件路径
152
+ * @returns {string} 解析后的路径
153
+ */
154
+ resolveRelativePath(componentPath, pageFilePath) {
155
+ const lastIndex = pageFilePath.lastIndexOf("/");
156
+ const newPath = pageFilePath.slice(0, lastIndex);
157
+ const res = path.resolve(newPath, componentPath);
158
+ return res.replace(this.workPath, "");
159
+ }
160
+ /**
161
+ * 解析 npm 组件
162
+ * @param {string} componentName 组件名称
163
+ * @param {string} pageFilePath 页面文件路径
164
+ * @returns {string|null} 解析后的组件路径,如果找不到返回 null
165
+ */
166
+ resolveNpmComponent(componentName, pageFilePath) {
167
+ const searchPaths = this.generateSearchPaths(pageFilePath);
168
+ for (const searchPath of searchPaths) {
169
+ const componentPath = this.findComponentInMiniprogramNpm(componentName, searchPath);
170
+ if (componentPath) {
171
+ return componentPath;
172
+ }
173
+ }
174
+ return null;
175
+ }
176
+ /**
177
+ * 生成 miniprogram_npm 搜索路径
178
+ * 按照微信小程序的寻址顺序生成搜索路径
179
+ * @param {string} pageFilePath 页面文件路径
180
+ * @returns {string[]} 搜索路径数组
181
+ */
182
+ generateSearchPaths(pageFilePath) {
183
+ const relativePath = pageFilePath.replace(this.workPath, "").replace(/^\//, "");
184
+ const pathParts = relativePath.split("/").slice(0, -1);
185
+ const searchPaths = [];
186
+ for (let i = pathParts.length; i >= 0; i--) {
187
+ const currentPath = pathParts.slice(0, i).join("/");
188
+ const miniprogramNpmPath = currentPath ? `${currentPath}/miniprogram_npm` : "miniprogram_npm";
189
+ searchPaths.push(miniprogramNpmPath);
190
+ }
191
+ return searchPaths;
192
+ }
193
+ /**
194
+ * 在指定的 miniprogram_npm 目录中查找组件
195
+ * @param {string} componentName 组件名称
196
+ * @param {string} miniprogramNpmPath miniprogram_npm 路径
197
+ * @returns {string|null} 组件路径,如果找不到返回 null
198
+ */
199
+ findComponentInMiniprogramNpm(componentName, miniprogramNpmPath) {
200
+ const fullMiniprogramNpmPath = path.join(this.workPath, miniprogramNpmPath);
201
+ if (!fs.existsSync(fullMiniprogramNpmPath)) {
202
+ return null;
203
+ }
204
+ const cacheKey = `${miniprogramNpmPath}/${componentName}`;
205
+ if (this.miniprogramNpmCache.has(cacheKey)) {
206
+ return this.miniprogramNpmCache.get(cacheKey);
207
+ }
208
+ const candidatePaths = [
209
+ componentName,
210
+ `${componentName}/index`
211
+ ];
212
+ for (const candidatePath of candidatePaths) {
213
+ const componentDir = path.join(fullMiniprogramNpmPath, candidatePath);
214
+ if (this.isValidComponent(componentDir)) {
215
+ const resolvedPath = `/${miniprogramNpmPath}/${candidatePath}`.replace(/\/+/g, "/");
216
+ this.miniprogramNpmCache.set(cacheKey, resolvedPath);
217
+ return resolvedPath;
218
+ }
219
+ }
220
+ this.miniprogramNpmCache.set(cacheKey, null);
221
+ return null;
222
+ }
223
+ /**
224
+ * 检查是否为有效的组件
225
+ * @param {string} componentPath 组件路径
226
+ * @returns {boolean} 是否为有效组件
227
+ */
228
+ isValidComponent(componentPath) {
229
+ const requiredFiles = [".json", ".js"];
230
+ const hasRequiredFiles = requiredFiles.some((ext) => {
231
+ return fs.existsSync(`${componentPath}${ext}`);
232
+ });
233
+ if (!hasRequiredFiles) {
234
+ const indexFiles = requiredFiles.some((ext) => {
235
+ return fs.existsSync(path.join(componentPath, `index${ext}`));
236
+ });
237
+ if (!indexFiles) {
238
+ return false;
239
+ }
240
+ const indexJsonFile = path.join(componentPath, "index.json");
241
+ if (fs.existsSync(indexJsonFile)) {
242
+ try {
243
+ const config = JSON.parse(fs.readFileSync(indexJsonFile, "utf-8"));
244
+ return config.component === true;
245
+ } catch (e) {
246
+ return false;
247
+ }
248
+ }
249
+ return true;
250
+ }
251
+ const jsonFile = `${componentPath}.json`;
252
+ if (fs.existsSync(jsonFile)) {
253
+ try {
254
+ const config = JSON.parse(fs.readFileSync(jsonFile, "utf-8"));
255
+ return config.component === true;
256
+ } catch (e) {
257
+ return false;
258
+ }
259
+ }
260
+ return true;
261
+ }
262
+ /**
263
+ * 获取 npm 包信息
264
+ * @param {string} packageName 包名
265
+ * @param {string} searchPath 搜索路径
266
+ * @returns {object|null} 包信息,如果找不到返回 null
267
+ */
268
+ getPackageInfo(packageName, searchPath) {
269
+ const cacheKey = `${searchPath}/${packageName}`;
270
+ if (this.packageCache.has(cacheKey)) {
271
+ return this.packageCache.get(cacheKey);
272
+ }
273
+ const packageJsonPath = path.join(this.workPath, searchPath, packageName, "package.json");
274
+ if (!fs.existsSync(packageJsonPath)) {
275
+ this.packageCache.set(cacheKey, null);
276
+ return null;
277
+ }
278
+ try {
279
+ const packageInfo = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
280
+ this.packageCache.set(cacheKey, packageInfo);
281
+ return packageInfo;
282
+ } catch (e) {
283
+ this.packageCache.set(cacheKey, null);
284
+ return null;
285
+ }
286
+ }
287
+ /**
288
+ * 清除缓存
289
+ */
290
+ clearCache() {
291
+ this.miniprogramNpmCache.clear();
292
+ this.packageCache.clear();
293
+ }
294
+ }
295
+ let pathInfo = {};
296
+ let configInfo = {};
297
+ let npmResolver = null;
298
+ function storeInfo(workPath) {
299
+ storePathInfo(workPath);
300
+ storeProjectConfig();
301
+ storeAppConfig();
302
+ storePageConfig();
303
+ return {
304
+ pathInfo,
305
+ configInfo
306
+ };
307
+ }
308
+ function resetStoreInfo(opts) {
309
+ pathInfo = opts.pathInfo;
310
+ configInfo = opts.configInfo;
311
+ if (pathInfo.workPath) {
312
+ npmResolver = new NpmResolver(pathInfo.workPath);
313
+ }
314
+ }
315
+ function storePathInfo(workPath) {
316
+ pathInfo.workPath = workPath;
317
+ if (process.env.TARGET_PATH) {
318
+ pathInfo.targetPath = process.env.TARGET_PATH;
319
+ } else {
320
+ const tempDir = process.env.GITHUB_WORKSPACE || os.tmpdir();
321
+ const targetDir = path.join(tempDir, `dimina-fe-dist-${Date.now()}`);
322
+ if (!fs.existsSync(targetDir)) {
323
+ fs.mkdirSync(targetDir, { recursive: true });
324
+ }
325
+ pathInfo.targetPath = targetDir;
326
+ }
327
+ npmResolver = new NpmResolver(workPath);
328
+ }
329
+ function storeProjectConfig() {
330
+ const privateConfigPath = `${pathInfo.workPath}/project.private.config.json`;
331
+ const defaultConfigPath = `${pathInfo.workPath}/project.config.json`;
332
+ let privateConfig = {};
333
+ let defaultConfig = {};
334
+ if (fs.existsSync(defaultConfigPath)) {
335
+ try {
336
+ defaultConfig = parseContentByPath(defaultConfigPath);
337
+ } catch (e) {
338
+ console.warn("Failed to parse project.config.json:", e.message);
339
+ }
340
+ }
341
+ if (fs.existsSync(privateConfigPath)) {
342
+ try {
343
+ privateConfig = parseContentByPath(privateConfigPath);
344
+ } catch (e) {
345
+ console.warn("Failed to parse project.private.config.json:", e.message);
346
+ }
347
+ }
348
+ configInfo.projectInfo = { ...defaultConfig, ...privateConfig };
349
+ }
350
+ function storeAppConfig() {
351
+ const filePath = `${pathInfo.workPath}/app.json`;
352
+ const content = parseContentByPath(filePath);
353
+ const newObj = {};
354
+ for (const key in content) {
355
+ if (Object.hasOwn(content, key)) {
356
+ if (key === "subpackages") {
357
+ newObj.subPackages = content[key];
358
+ } else {
359
+ newObj[key] = content[key];
360
+ }
361
+ }
362
+ }
363
+ configInfo.appInfo = newObj;
364
+ }
365
+ function getContentByPath(path2) {
366
+ return fs.readFileSync(path2, { encoding: "utf-8" });
367
+ }
368
+ function parseContentByPath(path2) {
369
+ return JSON.parse(getContentByPath(path2));
370
+ }
371
+ function storePageConfig() {
372
+ const { pages, subPackages } = configInfo.appInfo;
373
+ configInfo.pageInfo = {};
374
+ configInfo.componentInfo = {};
375
+ if (configInfo.appInfo.usingComponents) {
376
+ const appFilePath = `${pathInfo.workPath}/app.json`;
377
+ storeComponentConfig(configInfo.appInfo, appFilePath);
378
+ }
379
+ collectionPageJson(pages);
380
+ if (subPackages) {
381
+ subPackages.forEach((subPkg) => {
382
+ collectionPageJson(subPkg.pages, subPkg.root);
383
+ });
384
+ }
385
+ }
386
+ function collectionPageJson(pages, root) {
387
+ pages.forEach((pagePath) => {
388
+ let np = pagePath;
389
+ if (root) {
390
+ if (!root.endsWith("/")) {
391
+ root += "/";
392
+ }
393
+ np = root + np;
394
+ }
395
+ const pageFilePath = `${pathInfo.workPath}/${np}.json`;
396
+ if (fs.existsSync(pageFilePath)) {
397
+ const pageJsonContent = parseContentByPath(pageFilePath);
398
+ if (root) {
399
+ pageJsonContent.root = transSubDir(root);
400
+ }
401
+ configInfo.pageInfo[np] = pageJsonContent;
402
+ storeComponentConfig(pageJsonContent, pageFilePath);
403
+ }
404
+ });
405
+ }
406
+ function storeComponentConfig(pageJsonContent, pageFilePath) {
407
+ if (isObjectEmpty(pageJsonContent.usingComponents)) {
408
+ return;
409
+ }
410
+ for (const [componentName, componentPath] of Object.entries(pageJsonContent.usingComponents)) {
411
+ const moduleId = getModuleId(componentPath, pageFilePath);
412
+ pageJsonContent.usingComponents[componentName] = moduleId;
413
+ if (configInfo.componentInfo[moduleId]) {
414
+ continue;
415
+ }
416
+ let componentFilePath = path.resolve(getWorkPath(), `./${moduleId}.json`);
417
+ let cContent = null;
418
+ if (fs.existsSync(componentFilePath)) {
419
+ cContent = parseContentByPath(componentFilePath);
420
+ } else {
421
+ const indexJsonPath = path.resolve(getWorkPath(), `./${moduleId}/index.json`);
422
+ if (fs.existsSync(indexJsonPath)) {
423
+ componentFilePath = indexJsonPath;
424
+ cContent = parseContentByPath(componentFilePath);
425
+ } else {
426
+ if (moduleId.includes("/miniprogram_npm/")) {
427
+ console.log(`[env] 为 npm 组件创建默认配置: ${moduleId}`);
428
+ cContent = {
429
+ component: true,
430
+ usingComponents: {}
431
+ };
432
+ } else {
433
+ console.warn(`[env] 组件配置文件不存在: ${componentFilePath}`);
434
+ continue;
435
+ }
436
+ }
437
+ }
438
+ const cUsing = cContent.usingComponents || {};
439
+ const isComponent = cContent.component || false;
440
+ const cComponents = Object.keys(cUsing).reduce((acc, key) => {
441
+ acc[key] = getModuleId(cUsing[key], componentFilePath);
442
+ return acc;
443
+ }, {});
444
+ configInfo.componentInfo[moduleId] = {
445
+ id: uuid(),
446
+ path: moduleId,
447
+ component: isComponent,
448
+ usingComponents: cComponents
449
+ };
450
+ if (cContent.usingComponents && Object.keys(cContent.usingComponents).length > 0) {
451
+ storeComponentConfig(configInfo.componentInfo[moduleId], componentFilePath);
452
+ }
453
+ }
454
+ }
455
+ function getModuleId(src, pageFilePath) {
456
+ if (!npmResolver) {
457
+ const lastIndex = pageFilePath.lastIndexOf("/");
458
+ const newPath = pageFilePath.slice(0, lastIndex);
459
+ const workPath = getWorkPath();
460
+ const res = path.resolve(newPath, src);
461
+ return res.replace(workPath, "");
462
+ }
463
+ return npmResolver.resolveComponentPath(src, pageFilePath);
464
+ }
465
+ function getTargetPath() {
466
+ return pathInfo.targetPath;
467
+ }
468
+ function getComponent(src) {
469
+ return configInfo.componentInfo[src];
470
+ }
471
+ function getPageConfigInfo() {
472
+ return configInfo.pageInfo;
473
+ }
474
+ function getAppConfigInfo() {
475
+ return configInfo.appInfo;
476
+ }
477
+ function getWorkPath() {
478
+ return pathInfo.workPath;
479
+ }
480
+ function getAppId() {
481
+ return configInfo.projectInfo.appid;
482
+ }
483
+ function getAppName() {
484
+ if (configInfo.projectInfo.projectname) {
485
+ return decodeURIComponent(configInfo.projectInfo.projectname);
486
+ }
487
+ return getAppId();
488
+ }
489
+ function transSubDir(name) {
490
+ return `sub_${name.replace(/\/$/, "")}`;
491
+ }
492
+ function getPages() {
493
+ const { pages, subPackages = [], usingComponents: globalComponents = {} } = getAppConfigInfo();
494
+ const pageInfo = getPageConfigInfo();
495
+ const mainPages = pages.map((path2) => {
496
+ const pageComponents = pageInfo[path2]?.usingComponents || {};
497
+ const mergedComponents = { ...globalComponents, ...pageComponents };
498
+ return {
499
+ id: uuid(),
500
+ path: path2,
501
+ usingComponents: mergedComponents
502
+ };
503
+ });
504
+ const subPages = {};
505
+ subPackages.forEach((subPkg) => {
506
+ const rootPath = subPkg.root.endsWith("/") ? subPkg.root : `${subPkg.root}/`;
507
+ const independent = subPkg.independent ? subPkg.independent : false;
508
+ subPages[transSubDir(rootPath)] = {
509
+ independent,
510
+ info: subPkg.pages.map((path2) => {
511
+ const fullPath = rootPath + path2;
512
+ const pageComponents = pageInfo[fullPath]?.usingComponents || {};
513
+ const mergedComponents = { ...globalComponents, ...pageComponents };
514
+ return {
515
+ id: uuid(),
516
+ path: fullPath,
517
+ usingComponents: mergedComponents
518
+ };
519
+ })
520
+ };
521
+ });
522
+ return {
523
+ mainPages,
524
+ subPages
525
+ };
526
+ }
527
+ export {
528
+ getComponent as a,
529
+ getContentByPath as b,
530
+ getAbsolutePath as c,
531
+ getWorkPath as d,
532
+ collectAssets as e,
533
+ getAppId as f,
534
+ getTargetPath as g,
535
+ tagWhiteList as h,
536
+ hasCompileInfo as i,
537
+ getAppConfigInfo as j,
538
+ getAppName as k,
539
+ getPageConfigInfo as l,
540
+ getPages as m,
541
+ resetStoreInfo as r,
542
+ storeInfo as s,
543
+ transformRpx as t
544
+ };