miaoda-expo-devkit 0.1.1-beta.7 → 0.1.1-beta.9

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.
@@ -14,8 +14,10 @@ import { types, PluginObj } from '@babel/core';
14
14
  *
15
15
  * 对于纯文本节点:
16
16
  * <div>hello world</div>
17
+ * <div>{"hello world"}</div>
17
18
  * 转换后:
18
19
  * <div dataSet={{"mdId": "path/to/file.tsx:10:4", "componentContent": "{\"text\":\"hello world\"}"}}>hello world</div>
20
+ * <div dataSet={{"mdId": "path/to/file.tsx:11:4", "componentContent": "{\"text\":\"hello world\"}"}}>{"hello world"}</div>
19
21
  *
20
22
  * 用法(babel.config.js):
21
23
  *
@@ -69,9 +69,18 @@ function getTextNodeContent(t, path) {
69
69
  const children = parent.children;
70
70
  if (children.length !== 1) return null;
71
71
  const child = children[0];
72
- if (!t.isJSXText(child)) return null;
73
- const text = child.value.trim();
74
- return text || null;
72
+ if (t.isJSXText(child)) {
73
+ const text = child.value.trim();
74
+ return text || null;
75
+ }
76
+ if (t.isJSXExpressionContainer(child) && t.isStringLiteral(child.expression)) {
77
+ const text = child.expression.value.trim();
78
+ return text || null;
79
+ }
80
+ if (t.isJSXExpressionContainer(child) && t.isNumericLiteral(child.expression)) {
81
+ return String(child.expression.value);
82
+ }
83
+ return null;
75
84
  }
76
85
  function shouldSkipElement(t, name) {
77
86
  if (t.isJSXIdentifier(name)) {
package/dist/metro.d.mts CHANGED
@@ -192,11 +192,19 @@ declare function withDevStubs(config: MetroConfig): MetroConfig;
192
192
  * 适用场景:node_modules 位于 projectRoot 的祖先目录(如 /workspace/node_modules),
193
193
  * 而 projectRoot 自身的 node_modules 为空目录或不存在。
194
194
  *
195
- * 问题:Metro 只监听 projectRoot,不会自动爬取祖先目录的 node_modules,
196
- * 导致 Metro 无法在 file map 中找到依赖的真实路径,bundle 请求返回 404。
197
- *
198
- * 修复:将祖先目录中的 node_modules 加入 watchFolders 和 resolver.nodeModulesPaths,
199
- * 使 Metro 能正确索引并解析其中的模块。
195
+ * 问题:
196
+ * 1. Metro 只监听 projectRoot,祖先目录的 node_modules 不在 watchFolders 内,
197
+ * 导致模块无法被 file map 索引。
198
+ * 2. pnpm .pnpm 目录可能是指向外部路径的 symlink
199
+ * (如 /workspace/node_modules/.pnpm → /data/expo/node_modules/.pnpm)。
200
+ * Metro 跟随 symlink 后,将文件以真实路径(/data/expo/...)存入 file map,
201
+ * HTML 入口的 bundle URL 也随之变为 /data/expo/...bundle。
202
+ * 若 /data/expo/node_modules/ 不在 watchFolders,Metro HTTP server 会返回 404。
203
+ *
204
+ * 修复:
205
+ * 1. 将祖先目录的 node_modules 加入 watchFolders 和 resolver.nodeModulesPaths。
206
+ * 2. 若该 node_modules 下的 .pnpm 是指向外部路径的 symlink,
207
+ * 同样将外部真实路径加入 watchFolders 和 resolver.nodeModulesPaths。
200
208
  *
201
209
  * 用法(metro.config.js):
202
210
  * const { withWorkspaceNodeModules } = require('miaoda-expo-devkit/metro');
package/dist/metro.d.ts CHANGED
@@ -192,11 +192,19 @@ declare function withDevStubs(config: MetroConfig): MetroConfig;
192
192
  * 适用场景:node_modules 位于 projectRoot 的祖先目录(如 /workspace/node_modules),
193
193
  * 而 projectRoot 自身的 node_modules 为空目录或不存在。
194
194
  *
195
- * 问题:Metro 只监听 projectRoot,不会自动爬取祖先目录的 node_modules,
196
- * 导致 Metro 无法在 file map 中找到依赖的真实路径,bundle 请求返回 404。
197
- *
198
- * 修复:将祖先目录中的 node_modules 加入 watchFolders 和 resolver.nodeModulesPaths,
199
- * 使 Metro 能正确索引并解析其中的模块。
195
+ * 问题:
196
+ * 1. Metro 只监听 projectRoot,祖先目录的 node_modules 不在 watchFolders 内,
197
+ * 导致模块无法被 file map 索引。
198
+ * 2. pnpm .pnpm 目录可能是指向外部路径的 symlink
199
+ * (如 /workspace/node_modules/.pnpm → /data/expo/node_modules/.pnpm)。
200
+ * Metro 跟随 symlink 后,将文件以真实路径(/data/expo/...)存入 file map,
201
+ * HTML 入口的 bundle URL 也随之变为 /data/expo/...bundle。
202
+ * 若 /data/expo/node_modules/ 不在 watchFolders,Metro HTTP server 会返回 404。
203
+ *
204
+ * 修复:
205
+ * 1. 将祖先目录的 node_modules 加入 watchFolders 和 resolver.nodeModulesPaths。
206
+ * 2. 若该 node_modules 下的 .pnpm 是指向外部路径的 symlink,
207
+ * 同样将外部真实路径加入 watchFolders 和 resolver.nodeModulesPaths。
200
208
  *
201
209
  * 用法(metro.config.js):
202
210
  * const { withWorkspaceNodeModules } = require('miaoda-expo-devkit/metro');
package/dist/metro.js CHANGED
@@ -213,16 +213,33 @@ function findAncestorNodeModulesDir(projectRoot) {
213
213
  }
214
214
  return null;
215
215
  }
216
+ function resolveExternalPnpmStore(nodeModulesDir) {
217
+ const pnpmDir = import_path5.default.join(nodeModulesDir, ".pnpm");
218
+ try {
219
+ const realPnpmDir = import_fs2.default.realpathSync(pnpmDir);
220
+ const realNmDir = import_path5.default.dirname(realPnpmDir);
221
+ if (realNmDir !== nodeModulesDir) {
222
+ return realNmDir;
223
+ }
224
+ } catch {
225
+ }
226
+ return null;
227
+ }
216
228
  function withWorkspaceNodeModules(config) {
217
229
  const projectRoot = config.projectRoot ?? process.cwd();
218
230
  const found = findAncestorNodeModulesDir(projectRoot);
219
231
  if (!found) return config;
232
+ const foldersToAdd = [found];
233
+ const externalStore = resolveExternalPnpmStore(found);
234
+ if (externalStore) {
235
+ foldersToAdd.push(externalStore);
236
+ }
220
237
  return {
221
238
  ...config,
222
- watchFolders: [...config.watchFolders ?? [], found],
239
+ watchFolders: [...config.watchFolders ?? [], ...foldersToAdd],
223
240
  resolver: {
224
241
  ...config.resolver,
225
- nodeModulesPaths: [...config.resolver?.nodeModulesPaths ?? [], found]
242
+ nodeModulesPaths: [...config.resolver?.nodeModulesPaths ?? [], ...foldersToAdd]
226
243
  }
227
244
  };
228
245
  }
package/dist/metro.mjs CHANGED
@@ -177,16 +177,33 @@ function findAncestorNodeModulesDir(projectRoot) {
177
177
  }
178
178
  return null;
179
179
  }
180
+ function resolveExternalPnpmStore(nodeModulesDir) {
181
+ const pnpmDir = path5.join(nodeModulesDir, ".pnpm");
182
+ try {
183
+ const realPnpmDir = fs2.realpathSync(pnpmDir);
184
+ const realNmDir = path5.dirname(realPnpmDir);
185
+ if (realNmDir !== nodeModulesDir) {
186
+ return realNmDir;
187
+ }
188
+ } catch {
189
+ }
190
+ return null;
191
+ }
180
192
  function withWorkspaceNodeModules(config) {
181
193
  const projectRoot = config.projectRoot ?? process.cwd();
182
194
  const found = findAncestorNodeModulesDir(projectRoot);
183
195
  if (!found) return config;
196
+ const foldersToAdd = [found];
197
+ const externalStore = resolveExternalPnpmStore(found);
198
+ if (externalStore) {
199
+ foldersToAdd.push(externalStore);
200
+ }
184
201
  return {
185
202
  ...config,
186
- watchFolders: [...config.watchFolders ?? [], found],
203
+ watchFolders: [...config.watchFolders ?? [], ...foldersToAdd],
187
204
  resolver: {
188
205
  ...config.resolver,
189
- nodeModulesPaths: [...config.resolver?.nodeModulesPaths ?? [], found]
206
+ nodeModulesPaths: [...config.resolver?.nodeModulesPaths ?? [], ...foldersToAdd]
190
207
  }
191
208
  };
192
209
  }
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/rules/no-missing-css-import.ts
31
+ var no_missing_css_import_exports = {};
32
+ __export(no_missing_css_import_exports, {
33
+ default: () => no_missing_css_import_default
34
+ });
35
+ module.exports = __toCommonJS(no_missing_css_import_exports);
36
+ var import_node_fs = __toESM(require("fs"));
37
+ var import_node_path = __toESM(require("path"));
38
+ var import_oxc_resolver = require("oxc-resolver");
39
+ var CSS_EXTENSION = /\.css$/i;
40
+ var resolverCache = /* @__PURE__ */ new Map();
41
+ function getResolver(projectRoot) {
42
+ let resolver = resolverCache.get(projectRoot);
43
+ if (!resolver) {
44
+ resolver = new import_oxc_resolver.ResolverFactory({
45
+ extensions: [".css"],
46
+ conditionNames: ["import", "require", "node", "default"]
47
+ });
48
+ resolverCache.set(projectRoot, resolver);
49
+ }
50
+ return resolver;
51
+ }
52
+ function findProjectRoot(startPath) {
53
+ let dir = import_node_path.default.dirname(startPath);
54
+ while (dir !== import_node_path.default.dirname(dir)) {
55
+ if (import_node_fs.default.existsSync(import_node_path.default.join(dir, "package.json"))) return dir;
56
+ dir = import_node_path.default.dirname(dir);
57
+ }
58
+ return dir;
59
+ }
60
+ var noMissingCssImportRule = {
61
+ meta: {
62
+ type: "problem",
63
+ docs: {
64
+ description: "Disallow CSS imports that reference non-existent files."
65
+ },
66
+ schema: [],
67
+ messages: {
68
+ cssNotFound: "CSS file '{{source}}' does not exist."
69
+ }
70
+ },
71
+ create(context) {
72
+ const projectRoot = findProjectRoot(context.filename);
73
+ const resolver = getResolver(projectRoot);
74
+ const currentDir = import_node_path.default.dirname(context.filename);
75
+ function check(node, source) {
76
+ if (!CSS_EXTENSION.test(source)) return;
77
+ try {
78
+ const result = resolver.sync(currentDir, source);
79
+ if (!result.path || !import_node_fs.default.existsSync(result.path)) {
80
+ context.report({ node, messageId: "cssNotFound", data: { source } });
81
+ }
82
+ } catch {
83
+ context.report({ node, messageId: "cssNotFound", data: { source } });
84
+ }
85
+ }
86
+ return {
87
+ ImportDeclaration(node) {
88
+ check(node, node.source.value);
89
+ }
90
+ };
91
+ }
92
+ };
93
+ var plugin = {
94
+ meta: { name: "css-import" },
95
+ rules: { "no-missing-css-import": noMissingCssImportRule }
96
+ };
97
+ var no_missing_css_import_default = plugin;
98
+ module.exports = module.exports.default;
@@ -5,7 +5,8 @@
5
5
  { "name": "expo-config-plugin", "specifier": "miaoda-expo-devkit/rules/no-undeclared-expo-plugin" },
6
6
  { "name": "expo-router", "specifier": "miaoda-expo-devkit/rules/no-unstable-expo-router" },
7
7
  { "name": "rn-web", "specifier": "miaoda-expo-devkit/rules/no-rn-alert" },
8
- { "name": "expo-router-url", "specifier": "miaoda-expo-devkit/rules/no-duplicate-expo-router-url" }
8
+ { "name": "expo-router-url", "specifier": "miaoda-expo-devkit/rules/no-duplicate-expo-router-url" },
9
+ { "name": "css-import", "specifier": "miaoda-expo-devkit/rules/no-missing-css-import" }
9
10
  ],
10
11
 
11
12
  "categories": {
@@ -17,6 +18,7 @@
17
18
  "expo-router/no-unstable-expo-router": "error",
18
19
  "rn-web/no-rn-alert": "error",
19
20
  "expo-router-url/no-duplicate-expo-router-url": "error",
21
+ "css-import/no-missing-css-import": "error",
20
22
 
21
23
  "expo/no-dynamic-env-var": "error",
22
24
  "expo/no-env-var-destructuring": "error",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miaoda-expo-devkit",
3
- "version": "0.1.1-beta.7",
3
+ "version": "0.1.1-beta.9",
4
4
  "description": "Expo 应用开发工具集:Sentry DSN 替换 stub、错误/网络捕获、Metro 符号化",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
@@ -44,6 +44,7 @@
44
44
  "./rules/no-unstable-expo-router": "./dist/rules/no-unstable-expo-router.js",
45
45
  "./rules/no-rn-alert": "./dist/rules/no-rn-alert.js",
46
46
  "./rules/no-duplicate-expo-router-url": "./dist/rules/no-duplicate-expo-router-url.js",
47
+ "./rules/no-missing-css-import": "./dist/rules/no-missing-css-import.js",
47
48
  "./biome": "./biome-config.json",
48
49
  "./oxlint": "./oxlint-config.json"
49
50
  },
@@ -69,6 +70,7 @@
69
70
  "dependencies": {
70
71
  "connect": "^3.7.0",
71
72
  "es-toolkit": "^1.45.1",
73
+ "oxc-resolver": "^11.19.1",
72
74
  "stacktrace-parser": "^0.1.11"
73
75
  },
74
76
  "peerDependencies": {