miaoda-expo-devkit 0.1.1-beta.2 → 0.1.1-beta.21

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,28 @@
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 __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var ExpoCamera = __toESM(require("expo-camera"));
25
+ var import_nativewind = require("nativewind");
26
+ (0, import_nativewind.cssInterop)(ExpoCamera.CameraView, { className: "style" });
27
+ module.exports = ExpoCamera;
28
+ //# sourceMappingURL=expo-camera-stub.js.map
@@ -0,0 +1,28 @@
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 __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var ExpoImage = __toESM(require("expo-image"));
25
+ var import_nativewind = require("nativewind");
26
+ (0, import_nativewind.cssInterop)(ExpoImage.Image, { className: "style" });
27
+ module.exports = ExpoImage;
28
+ //# sourceMappingURL=expo-image-stub.js.map
@@ -0,0 +1,28 @@
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 __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var ExpoLinearGradient = __toESM(require("expo-linear-gradient"));
25
+ var import_nativewind = require("nativewind");
26
+ (0, import_nativewind.cssInterop)(ExpoLinearGradient.LinearGradient, { className: "style" });
27
+ module.exports = ExpoLinearGradient;
28
+ //# sourceMappingURL=expo-linear-gradient-stub.js.map
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ var import_expo = require("expo");
3
+ var import_react_native = require("react-native");
4
+ if (!(0, import_expo.isRunningInExpoGo)()) {
5
+ module.exports = require("expo-notifications");
6
+ } else {
7
+ let showDetailedAlert = function(apiName, lines, isValid, errors) {
8
+ const statusLine = isValid ? "\u79D2\u54D2\u901A\u77E5\u60A8 \u6D88\u606F\u63A8\u9001\u9A8C\u8BC1\u901A\u8FC7" : "\u9A8C\u8BC1\u672A\u901A\u8FC7";
9
+ const parts = [statusLine, "", ...lines];
10
+ if (!isValid && errors && errors.length > 0) {
11
+ parts.push("");
12
+ parts.push(`\u95EE\u9898: ${errors.join(" / ")}`);
13
+ parts.push("");
14
+ parts.push("\u8BF7\u524D\u5F80\u79D2\u54D2\u5E73\u53F0\u4FEE\u6539\u901A\u77E5\u914D\u7F6E\u540E\u91CD\u65B0\u9A8C\u8BC1");
15
+ } else {
16
+ parts.push("");
17
+ parts.push("\u901A\u77E5\u914D\u7F6E\u6B63\u786E\uFF0C\u53EF\u4EE5\u653E\u5FC3\u53D1\u5E03");
18
+ }
19
+ import_react_native.Alert.alert(apiName, parts.join("\n"), [{ text: "\u77E5\u9053\u4E86" }]);
20
+ }, formatScheduleRequest = function(request) {
21
+ if (!request || typeof request !== "object") {
22
+ return ["request: (\u65E0\u6548\u503C)"];
23
+ }
24
+ const req = request;
25
+ const content = req["content"] && typeof req["content"] === "object" ? req["content"] : void 0;
26
+ const trigger = req["trigger"];
27
+ const lines = [];
28
+ const titleVal = content?.["title"];
29
+ const bodyVal = content?.["body"];
30
+ lines.push(`\u901A\u77E5\u6807\u9898: ${titleVal != null ? JSON.stringify(String(titleVal)) : "(\u672A\u586B\u5199)"}`);
31
+ lines.push(`\u901A\u77E5\u5185\u5BB9: ${bodyVal != null ? JSON.stringify(String(bodyVal)) : "(\u672A\u586B\u5199)"}`);
32
+ if (content?.["subtitle"] != null) {
33
+ const sub = JSON.stringify(String(content["subtitle"]));
34
+ lines.push(`\u526F\u6807\u9898: ${sub.length > 42 ? sub.slice(0, 42) + "\u2026" : sub}`);
35
+ }
36
+ if (content?.["data"] != null) {
37
+ const dataStr = JSON.stringify(content["data"]);
38
+ lines.push(`\u9644\u52A0\u6570\u636E: ${dataStr.length > 40 ? dataStr.slice(0, 40) + "\u2026" : dataStr}`);
39
+ }
40
+ if (trigger == null) {
41
+ lines.push("\u53D1\u9001\u65F6\u673A: \u7ACB\u5373\u53D1\u9001");
42
+ } else if (typeof trigger === "object") {
43
+ const t = trigger;
44
+ if (t["type"] === "timeInterval") {
45
+ lines.push(`\u53D1\u9001\u65F6\u673A: ${String(t["seconds"])} \u79D2\u540E`);
46
+ } else if (t["type"] === "date") {
47
+ lines.push(`\u53D1\u9001\u65F6\u673A: \u6307\u5B9A\u65F6\u95F4 ${String(t["value"] ?? "(\u672A\u77E5)")}`);
48
+ } else {
49
+ const ts = JSON.stringify(trigger);
50
+ lines.push(`\u53D1\u9001\u65F6\u673A: ${ts.length > 40 ? ts.slice(0, 40) + "\u2026" : ts}`);
51
+ }
52
+ } else {
53
+ lines.push(`\u53D1\u9001\u65F6\u673A: ${String(trigger)}`);
54
+ }
55
+ return lines;
56
+ }, validateScheduleRequest = function(request) {
57
+ const errors = [];
58
+ if (!request || typeof request !== "object") {
59
+ errors.push("request \u4E0D\u80FD\u4E3A\u7A7A");
60
+ return { ok: false, errors };
61
+ }
62
+ const req = request;
63
+ if (!req["content"] || typeof req["content"] !== "object") {
64
+ errors.push("request.content \u4E0D\u80FD\u4E3A\u7A7A");
65
+ return { ok: false, errors };
66
+ }
67
+ const content = req["content"];
68
+ const titleOk = typeof content["title"] === "string" && content["title"].trim().length > 0;
69
+ const bodyOk = typeof content["body"] === "string" && content["body"].trim().length > 0;
70
+ if (!titleOk && !bodyOk) {
71
+ errors.push("content.title \u548C content.body \u5747\u4E3A\u7A7A");
72
+ }
73
+ const trigger = req["trigger"];
74
+ if (trigger != null && typeof trigger === "object") {
75
+ const t = trigger;
76
+ if (t["type"] === "timeInterval") {
77
+ if (typeof t["seconds"] !== "number" || t["seconds"] <= 0) {
78
+ errors.push("trigger.seconds \u5FC5\u987B > 0");
79
+ }
80
+ }
81
+ }
82
+ return { ok: errors.length === 0, errors };
83
+ }, validateChannel = function(channelId, channel) {
84
+ const errors = [];
85
+ if (typeof channelId !== "string" || channelId.trim().length === 0) {
86
+ errors.push("channelId \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
87
+ }
88
+ if (!channel || typeof channel !== "object") {
89
+ errors.push("channel \u4E0D\u80FD\u4E3A\u7A7A");
90
+ return { ok: false, errors };
91
+ }
92
+ const ch = channel;
93
+ if (typeof ch["name"] !== "string" || ch["name"].trim().length === 0) {
94
+ errors.push("channel.name \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
95
+ }
96
+ return { ok: errors.length === 0, errors };
97
+ };
98
+ var showDetailedAlert2 = showDetailedAlert, formatScheduleRequest2 = formatScheduleRequest, validateScheduleRequest2 = validateScheduleRequest, validateChannel2 = validateChannel;
99
+ const DENIED_PERMISSION = {
100
+ status: "denied",
101
+ granted: false,
102
+ canAskAgain: false,
103
+ expires: "never"
104
+ };
105
+ const handleRequestPermissionsAsync = async () => {
106
+ showDetailedAlert(
107
+ "\u8BF7\u6C42\u901A\u77E5\u6743\u9650",
108
+ ["\u626B\u7801\u9884\u89C8\u73AF\u5883\u6A21\u62DF\u8FD4\u56DE\u672A\u6388\u6743", "\u53D1\u5E03\u540E\u4F1A\u5411\u7528\u6237\u5F39\u51FA\u7CFB\u7EDF\u6388\u6743\u5F39\u7A97"],
109
+ true
110
+ );
111
+ return DENIED_PERMISSION;
112
+ };
113
+ const handleSetNotificationChannelAsync = async (channelId, channel) => {
114
+ const { ok, errors } = validateChannel(channelId, channel);
115
+ const ch = channel && typeof channel === "object" ? channel : {};
116
+ const chStr = JSON.stringify(channel);
117
+ const lines = [
118
+ `\u6E20\u9053 ID: ${JSON.stringify(channelId)}`,
119
+ `\u6E20\u9053\u540D\u79F0: ${JSON.stringify(ch["name"] ?? "(\u672A\u8BBE\u7F6E)")}`,
120
+ `\u5B8C\u6574\u914D\u7F6E: ${chStr.length > 60 ? chStr.slice(0, 60) + "\u2026" : chStr}`
121
+ ];
122
+ showDetailedAlert("\u521B\u5EFA\u901A\u77E5\u6E20\u9053", lines, ok, ok ? void 0 : errors);
123
+ return null;
124
+ };
125
+ const handleScheduleNotificationAsync = async (request) => {
126
+ const { ok, errors } = validateScheduleRequest(request);
127
+ const lines = formatScheduleRequest(request);
128
+ showDetailedAlert("\u53D1\u9001\u672C\u5730\u901A\u77E5", lines, ok, ok ? void 0 : errors);
129
+ return void 0;
130
+ };
131
+ const noopPermission = async () => DENIED_PERMISSION;
132
+ const noopListener = () => ({ remove: () => {
133
+ } });
134
+ const noop = async () => void 0;
135
+ const enums = {
136
+ AndroidNotificationPriority: {
137
+ MIN: "min",
138
+ LOW: "low",
139
+ DEFAULT: "default",
140
+ HIGH: "high",
141
+ MAX: "max"
142
+ },
143
+ AndroidImportance: { NONE: 0, MIN: 1, LOW: 2, DEFAULT: 3, HIGH: 4, MAX: 5 },
144
+ SchedulableTriggerInputTypes: {
145
+ DATE: "date",
146
+ TIME_INTERVAL: "timeInterval",
147
+ CALENDAR: "calendar",
148
+ DAILY: "daily",
149
+ WEEKLY: "weekly",
150
+ YEARLY: "yearly"
151
+ }
152
+ };
153
+ const coreHandlers = {
154
+ requestPermissionsAsync: handleRequestPermissionsAsync,
155
+ setNotificationChannelAsync: handleSetNotificationChannelAsync,
156
+ scheduleNotificationAsync: handleScheduleNotificationAsync
157
+ };
158
+ module.exports = new Proxy(enums, {
159
+ get(target, key) {
160
+ if (key in target) return target[key];
161
+ if (key in coreHandlers) return coreHandlers[key];
162
+ if (key.endsWith("PermissionsAsync")) return noopPermission;
163
+ if (key.endsWith("Listener")) return noopListener;
164
+ return noop;
165
+ }
166
+ });
167
+ }
168
+ //# sourceMappingURL=expo-notifications-stub.js.map
@@ -33,6 +33,20 @@ const THROTTLE_INTERVAL = 8;
33
33
  const THROTTLE_OPTIONS = {
34
34
  edges: ["leading", "trailing"]
35
35
  };
36
+ function isInsideSvgButNotSvgElement(el) {
37
+ const tag = el.tagName.toLowerCase();
38
+ return tag !== "svg" && el.closest("svg") !== null;
39
+ }
40
+ function getTargetElement(el) {
41
+ const tag = el.tagName.toLowerCase();
42
+ if (tag === "html") {
43
+ return null;
44
+ }
45
+ if (isInsideSvgButNotSvgElement(el)) {
46
+ return el.closest("svg");
47
+ }
48
+ return el;
49
+ }
36
50
  function isEditorMessage(data) {
37
51
  return typeof data === "object" && data !== null && typeof data.type === "string" && data.type.startsWith("editor-");
38
52
  }
@@ -43,7 +57,7 @@ function getFiber(el) {
43
57
  function isEditable(el) {
44
58
  return !!el && !!el.dataset.mdId;
45
59
  }
46
- function collectElementInfo(el) {
60
+ function collectElementInfo(el, siblingIndex) {
47
61
  if (!el) return null;
48
62
  const fiber = getFiber(el);
49
63
  const owner = fiber?._debugOwner;
@@ -53,7 +67,7 @@ function collectElementInfo(el) {
53
67
  const mdIdParts = componentId.split(":");
54
68
  const componentPath = mdIdParts[0];
55
69
  const componentLine = mdIdParts[1];
56
- const componentIndex = String(owner?.index ?? 0);
70
+ const componentIndex = String(siblingIndex ?? 0);
57
71
  const componentContent = JSON.parse(decodeURIComponent(el.dataset?.componentContent || "{}"));
58
72
  const rect = el.getBoundingClientRect();
59
73
  return {
@@ -124,7 +138,8 @@ class EditorController {
124
138
  * 设置当前悬停元素的 hover 样式
125
139
  */
126
140
  this.onMouseOver = (e) => {
127
- const node = e.target;
141
+ const rawNode = e.target;
142
+ const node = getTargetElement(rawNode);
128
143
  if (!isEditable(node)) return;
129
144
  if (this.hoverNode) {
130
145
  const isActive = this.activeNode === this.hoverNode;
@@ -150,7 +165,8 @@ class EditorController {
150
165
  this.onClick = (e) => {
151
166
  e.stopPropagation();
152
167
  e.preventDefault();
153
- const node = e.target;
168
+ const rawNode = e.target;
169
+ const node = getTargetElement(rawNode);
154
170
  if (!isEditable(node) || this.activeNode === node) return;
155
171
  this.stopObservingActiveNode();
156
172
  this.activeNode && removeActiveAttr(this.activeNode);
@@ -182,6 +198,20 @@ class EditorController {
182
198
  THROTTLE_INTERVAL,
183
199
  THROTTLE_OPTIONS
184
200
  );
201
+ /**
202
+ * 监听message消息,接收自父窗口发送的信息
203
+ */
204
+ this.onMessage = (e) => {
205
+ if (!isEditorMessage(e.data)) return;
206
+ switch (e.data.type) {
207
+ case "editor-clear-selection":
208
+ this.clearSelection();
209
+ break;
210
+ case "editor-delete":
211
+ this.deleteActiveNode();
212
+ break;
213
+ }
214
+ };
185
215
  }
186
216
  /**
187
217
  * 初始化编辑器
@@ -193,6 +223,7 @@ class EditorController {
193
223
  const { signal } = this.abortController;
194
224
  const opts = { capture: true, signal };
195
225
  this.removeSelectorStyle = (0, import_css_control.injectSelectorModeStyle)();
226
+ window.addEventListener("message", this.onMessage, { signal });
196
227
  document.addEventListener("mouseover", this.onMouseOver, opts);
197
228
  document.addEventListener("mouseleave", this.onMouseLeave, opts);
198
229
  document.addEventListener("click", this.onClick, opts);
@@ -218,7 +249,10 @@ class EditorController {
218
249
  /** 收集并发送选中节点信息 */
219
250
  postActiveInfo(node) {
220
251
  if (!node) return;
221
- const info = collectElementInfo(node);
252
+ const allSameId = [node, ...this.siblingNodes];
253
+ allSameId.sort((a, b) => a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
254
+ const siblingIndex = allSameId.indexOf(node);
255
+ const info = collectElementInfo(node, siblingIndex);
222
256
  if (info) postToParent("iframe-target-change", info);
223
257
  }
224
258
  /**
@@ -246,18 +280,46 @@ class EditorController {
246
280
  }
247
281
  /**
248
282
  * 根据mdId收集兄弟节点并高亮
249
- * 在父节点的直接子元素中查找所有具有相同 mdId 的元素
283
+ *
284
+ * 向上遍历祖先链,找到真正的"循环容器"——即其直接子元素中存在多个
285
+ * 相同 mdId 的那一层祖先。这样即使父节点本身也是循环组件的一部分,
286
+ * 也能正确定位到所有同名实例。
250
287
  */
251
288
  highlightSiblings(node) {
252
289
  const mdId = node.dataset.mdId;
253
290
  if (!mdId) return;
254
- const parent = node.parentElement;
255
- if (!parent) return;
256
- this.siblingNodes = Array.from(parent.children).filter((child) => child instanceof HTMLElement && child !== node && child.dataset.mdId === mdId);
291
+ const loopContainer = this.findLoopContainer(node, mdId);
292
+ if (!loopContainer) return;
293
+ const allMatches = loopContainer.querySelectorAll(`[data-md-id="${CSS.escape(mdId)}"]`);
294
+ this.siblingNodes = Array.from(allMatches).filter((el) => (el instanceof HTMLElement || el instanceof SVGSVGElement) && el !== node);
257
295
  for (const sibling of this.siblingNodes) {
258
296
  setSiblingAttr(sibling);
259
297
  }
260
298
  }
299
+ /**
300
+ * 向上遍历祖先链,找到包含循环实例的容器节点。
301
+ *
302
+ * 判断逻辑:从 node 的 parent 开始逐层向上,检查每一层祖先的
303
+ * 直接子元素中,有多少个"包含目标 mdId"的子树(子元素自身匹配
304
+ * 或其后代匹配均算)。≥2 个即认定该祖先为循环容器。
305
+ *
306
+ * 为避免遍历整个 document,最多向上查找 10 层。
307
+ */
308
+ findLoopContainer(node, mdId) {
309
+ const selector = `[data-md-id="${CSS.escape(mdId)}"]`;
310
+ let ancestor = node.parentElement;
311
+ const maxDepth = 10;
312
+ for (let i = 0; i < maxDepth && ancestor; i++) {
313
+ const directChildrenWithMatch = Array.from(ancestor.children).filter(
314
+ (child) => child.matches(selector) || child.querySelector(selector)
315
+ );
316
+ if (directChildrenWithMatch.length >= 2) {
317
+ return ancestor;
318
+ }
319
+ ancestor = ancestor.parentElement;
320
+ }
321
+ return null;
322
+ }
261
323
  /** 清除兄弟节点高亮 */
262
324
  clearSiblingHighlights() {
263
325
  for (const sibling of this.siblingNodes) {
@@ -265,6 +327,31 @@ class EditorController {
265
327
  }
266
328
  this.siblingNodes = [];
267
329
  }
330
+ /**
331
+ * 清除选中状态
332
+ * 移除 active 节点的选中样式、兄弟节点高亮、hover 状态,并停止属性观察
333
+ */
334
+ clearSelection() {
335
+ if (this.activeNode) {
336
+ this.stopObservingActiveNode();
337
+ removeActiveAttr(this.activeNode);
338
+ this.activeNode = null;
339
+ }
340
+ this.clearSiblingHighlights();
341
+ this.onMouseLeave();
342
+ }
343
+ /**
344
+ * 删除当前选中的元素
345
+ * 断开观察器,移除 DOM 节点,并通知父窗口清除状态
346
+ */
347
+ deleteActiveNode() {
348
+ if (!this.activeNode) return;
349
+ this.stopObservingActiveNode();
350
+ this.clearSiblingHighlights();
351
+ removeActiveAttr(this.activeNode);
352
+ this.activeNode = null;
353
+ postToParent("iframe-node-clear");
354
+ }
268
355
  }
269
356
  let controller = null;
270
357
  function onGlobalMessage(e) {
@@ -0,0 +1,49 @@
1
+ {
2
+ "plugins": ["typescript", "react"],
3
+ "jsPlugins": [
4
+ "eslint-plugin-expo",
5
+ { "name": "expo-config-plugin", "specifier": "miaoda-expo-devkit/rules/no-undeclared-expo-plugin" },
6
+ { "name": "expo-router", "specifier": "miaoda-expo-devkit/rules/no-unstable-expo-router" },
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" },
9
+ { "name": "css-import", "specifier": "miaoda-expo-devkit/rules/no-missing-css-import" }
10
+ ],
11
+
12
+ "categories": {
13
+ "correctness": "allow"
14
+ },
15
+
16
+ "rules": {
17
+ "expo-config-plugin/no-undeclared-expo-plugin": "error",
18
+ "expo-router/no-unstable-expo-router": "error",
19
+ "rn-web/no-rn-alert": "error",
20
+ "expo-router-url/no-duplicate-expo-router-url": "error",
21
+ "css-import/no-missing-css-import": "error",
22
+
23
+ "expo/no-dynamic-env-var": "error",
24
+ "expo/no-env-var-destructuring": "error",
25
+ "expo/use-dom-exports": "error",
26
+
27
+ "no-undef": "error",
28
+ "use-isnan": "error",
29
+ "valid-typeof": "error",
30
+ "no-dupe-keys": "error",
31
+ "no-duplicate-case": "error",
32
+ "no-dupe-class-members": "error",
33
+
34
+ "react/react-in-jsx-scope": "off",
35
+ "react/jsx-no-duplicate-props": "error",
36
+ "react/jsx-no-undef": "error"
37
+ },
38
+
39
+ "env": {
40
+ "browser": true
41
+ },
42
+
43
+ "globals": {
44
+ "__DEV__": "readonly",
45
+ "process": "readonly",
46
+ "global": "readonly",
47
+ "localStorage": "readonly"
48
+ }
49
+ }
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "miaoda-expo-devkit",
3
- "version": "0.1.1-beta.2",
3
+ "version": "0.1.1-beta.21",
4
4
  "description": "Expo 应用开发工具集:Sentry DSN 替换 stub、错误/网络捕获、Metro 符号化",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",
8
8
  "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "devkit-lint": "./dist/cli/lint.js"
11
+ },
9
12
  "exports": {
10
13
  ".": {
11
14
  "import": {
@@ -31,46 +34,88 @@
31
34
  "types": "./dist/babel/plugin-jsx-source.d.ts",
32
35
  "require": "./dist/babel/plugin-jsx-source.js"
33
36
  },
37
+ "./babel-plugin-lucide-react-native": {
38
+ "types": "./dist/babel/plugin-lucide-react-native.d.ts",
39
+ "require": "./dist/babel/plugin-lucide-react-native.js"
40
+ },
34
41
  "./babel-preset": {
35
42
  "types": "./dist/babel/preset.d.ts",
36
43
  "require": "./dist/babel/preset.js"
37
44
  },
38
45
  "./sentry-react-native-stub": "./dist/stubs/sentry-react-native-stub.js",
39
46
  "./no-op-logbox": "./dist/stubs/no-op-logbox.js",
47
+ "./expo-notifications-stub": "./dist/stubs/expo-notifications-stub.js",
40
48
  "./rules/no-undeclared-expo-plugin": "./dist/rules/no-undeclared-expo-plugin.js",
49
+ "./rules/no-unused-expo-plugin": "./dist/rules/no-unused-expo-plugin.js",
41
50
  "./rules/no-unstable-expo-router": "./dist/rules/no-unstable-expo-router.js",
42
51
  "./rules/no-rn-alert": "./dist/rules/no-rn-alert.js",
43
52
  "./rules/no-duplicate-expo-router-url": "./dist/rules/no-duplicate-expo-router-url.js",
44
- "./biome": "./biome-config.json"
53
+ "./rules/no-missing-css-import": "./dist/rules/no-missing-css-import.js",
54
+ "./biome": "./biome-config.json",
55
+ "./oxlint": "./oxlint-config.json",
56
+ "./tsconfig-base": "./tsconfig-base.json"
45
57
  },
46
58
  "files": [
47
59
  "dist",
48
60
  "biome-config.json",
61
+ "oxlint-config.json",
49
62
  "pnpm-config.json",
63
+ "tsconfig-base.json",
50
64
  "!dist/**/*.map"
51
65
  ],
52
66
  "scripts": {
53
67
  "build": "tsup",
54
- "prepare": "tsup",
55
68
  "typecheck": "tsc --noEmit && tsc -p tsconfig.check.json --noEmit",
56
69
  "test": "vitest run",
57
- "test:rules": "node --test --test-reporter=./src/rules/test-reporter.mjs src/rules/__tests__/*.test.ts",
58
- "prepublishOnly": "pnpm run test && pnpm run build",
59
70
  "release": "pnpm run test && pnpm run build && npm publish",
60
- "release:beta": "npm version prerelease --preid=beta && pnpm run test && pnpm run build && npm publish --tag beta",
61
- "release:patch": "npm version patch && pnpm run release",
62
- "release:minor": "npm version minor && pnpm run release",
63
- "release:major": "npm version major && pnpm run release"
71
+ "release:beta": "pnpm run test && pnpm run build && npm version prerelease --preid=beta && npm publish --tag beta",
72
+ "release:patch": "pnpm run test && pnpm run build && npm version patch && npm publish",
73
+ "release:minor": "pnpm run test && pnpm run build && npm version minor && npm publish",
74
+ "release:major": "pnpm run test && pnpm run build && npm version major && npm publish"
64
75
  },
65
76
  "dependencies": {
66
77
  "connect": "^3.7.0",
67
78
  "es-toolkit": "^1.45.1",
79
+ "metro-minify-esbuild": "^0.2.0",
80
+ "oxc-resolver": "^11.19.1",
68
81
  "stacktrace-parser": "^0.1.11"
69
82
  },
70
83
  "peerDependencies": {
71
84
  "@sentry/core": "^10.38.0",
72
85
  "@sentry/react-native": ">=8.0.0",
73
- "react-native": ">=0.72.0"
86
+ "metro": ">=0.80.0",
87
+ "metro-config": ">=0.80.0",
88
+ "metro-resolver": ">=0.80.0",
89
+ "nativewind": ">=4.0.0",
90
+ "react-native": ">=0.79.0",
91
+ "react-native-css-interop": ">=0.2.0",
92
+ "typescript": ">=5.0.0"
93
+ },
94
+ "peerDependenciesMeta": {
95
+ "@sentry/core": {
96
+ "optional": true
97
+ },
98
+ "@sentry/react-native": {
99
+ "optional": true
100
+ },
101
+ "metro": {
102
+ "optional": true
103
+ },
104
+ "metro-config": {
105
+ "optional": true
106
+ },
107
+ "metro-resolver": {
108
+ "optional": true
109
+ },
110
+ "nativewind": {
111
+ "optional": true
112
+ },
113
+ "react-native-css-interop": {
114
+ "optional": true
115
+ },
116
+ "typescript": {
117
+ "optional": true
118
+ }
74
119
  },
75
120
  "publishConfig": {
76
121
  "registry": "https://registry.npmjs.org/",
@@ -78,15 +123,18 @@
78
123
  },
79
124
  "devDependencies": {
80
125
  "@babel/core": "^7.26.0",
126
+ "@babel/helper-module-imports": "^7.28.6",
81
127
  "@sentry/core": "^10.38.0",
82
128
  "@sentry/react-native": ">=8.0.0",
83
129
  "@types/babel__core": "^7.20.5",
130
+ "@types/babel__helper-module-imports": "^7.18.3",
84
131
  "@types/connect": "^3.4.38",
85
132
  "@types/node": "^25.0.0",
133
+ "metro": "^0.83.0",
86
134
  "metro-config": "^0.83.0",
87
135
  "metro-resolver": "^0.83.0",
88
- "oxlint": "^1.60.0",
136
+ "oxlint": "catalog:",
89
137
  "tsup": "^8.5.1",
90
- "vitest": "^3.0.0"
138
+ "vitest": "^4.1.5"
91
139
  }
92
140
  }
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "expo/tsconfig.base",
4
+ "compilerOptions": {
5
+ "strict": true
6
+ }
7
+ }