miaoda-expo-devkit 0.1.1-beta.96 → 0.1.1-beta.97
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/dist/cli/lint.js
CHANGED
|
@@ -9089,29 +9089,27 @@ var require_has_flag = __commonJS({
|
|
|
9089
9089
|
}
|
|
9090
9090
|
});
|
|
9091
9091
|
|
|
9092
|
-
// ../../node_modules/.pnpm/supports-color@
|
|
9092
|
+
// ../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js
|
|
9093
9093
|
var require_supports_color = __commonJS({
|
|
9094
|
-
"../../node_modules/.pnpm/supports-color@
|
|
9094
|
+
"../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports2, module2) {
|
|
9095
9095
|
"use strict";
|
|
9096
9096
|
var os = require("os");
|
|
9097
9097
|
var tty = require("tty");
|
|
9098
9098
|
var hasFlag = require_has_flag();
|
|
9099
9099
|
var { env } = process;
|
|
9100
|
-
var
|
|
9100
|
+
var forceColor;
|
|
9101
9101
|
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
9102
|
-
|
|
9102
|
+
forceColor = 0;
|
|
9103
9103
|
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
9104
|
-
|
|
9104
|
+
forceColor = 1;
|
|
9105
9105
|
}
|
|
9106
|
-
|
|
9107
|
-
if (
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
}
|
|
9114
|
-
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
9106
|
+
if ("FORCE_COLOR" in env) {
|
|
9107
|
+
if (env.FORCE_COLOR === "true") {
|
|
9108
|
+
forceColor = 1;
|
|
9109
|
+
} else if (env.FORCE_COLOR === "false") {
|
|
9110
|
+
forceColor = 0;
|
|
9111
|
+
} else {
|
|
9112
|
+
forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3);
|
|
9115
9113
|
}
|
|
9116
9114
|
}
|
|
9117
9115
|
function translateLevel(level) {
|
|
@@ -9125,22 +9123,15 @@ var require_supports_color = __commonJS({
|
|
|
9125
9123
|
has16m: level >= 3
|
|
9126
9124
|
};
|
|
9127
9125
|
}
|
|
9128
|
-
function supportsColor(haveStream,
|
|
9129
|
-
const noFlagForceColor = envForceColor();
|
|
9130
|
-
if (noFlagForceColor !== void 0) {
|
|
9131
|
-
flagForceColor = noFlagForceColor;
|
|
9132
|
-
}
|
|
9133
|
-
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
9126
|
+
function supportsColor(haveStream, streamIsTTY) {
|
|
9134
9127
|
if (forceColor === 0) {
|
|
9135
9128
|
return 0;
|
|
9136
9129
|
}
|
|
9137
|
-
if (
|
|
9138
|
-
|
|
9139
|
-
|
|
9140
|
-
|
|
9141
|
-
|
|
9142
|
-
return 2;
|
|
9143
|
-
}
|
|
9130
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
9131
|
+
return 3;
|
|
9132
|
+
}
|
|
9133
|
+
if (hasFlag("color=256")) {
|
|
9134
|
+
return 2;
|
|
9144
9135
|
}
|
|
9145
9136
|
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
9146
9137
|
return 0;
|
|
@@ -9157,7 +9148,7 @@ var require_supports_color = __commonJS({
|
|
|
9157
9148
|
return 1;
|
|
9158
9149
|
}
|
|
9159
9150
|
if ("CI" in env) {
|
|
9160
|
-
if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE"
|
|
9151
|
+
if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
9161
9152
|
return 1;
|
|
9162
9153
|
}
|
|
9163
9154
|
return min;
|
|
@@ -9169,7 +9160,7 @@ var require_supports_color = __commonJS({
|
|
|
9169
9160
|
return 3;
|
|
9170
9161
|
}
|
|
9171
9162
|
if ("TERM_PROGRAM" in env) {
|
|
9172
|
-
const version =
|
|
9163
|
+
const version = parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
9173
9164
|
switch (env.TERM_PROGRAM) {
|
|
9174
9165
|
case "iTerm.app":
|
|
9175
9166
|
return version >= 3 ? 3 : 2;
|
|
@@ -9188,17 +9179,14 @@ var require_supports_color = __commonJS({
|
|
|
9188
9179
|
}
|
|
9189
9180
|
return min;
|
|
9190
9181
|
}
|
|
9191
|
-
function getSupportLevel(stream
|
|
9192
|
-
const level = supportsColor(stream,
|
|
9193
|
-
streamIsTTY: stream && stream.isTTY,
|
|
9194
|
-
...options
|
|
9195
|
-
});
|
|
9182
|
+
function getSupportLevel(stream) {
|
|
9183
|
+
const level = supportsColor(stream, stream && stream.isTTY);
|
|
9196
9184
|
return translateLevel(level);
|
|
9197
9185
|
}
|
|
9198
9186
|
module2.exports = {
|
|
9199
9187
|
supportsColor: getSupportLevel,
|
|
9200
|
-
stdout:
|
|
9201
|
-
stderr:
|
|
9188
|
+
stdout: translateLevel(supportsColor(true, tty.isatty(1))),
|
|
9189
|
+
stderr: translateLevel(supportsColor(true, tty.isatty(2)))
|
|
9202
9190
|
};
|
|
9203
9191
|
}
|
|
9204
9192
|
});
|
|
@@ -0,0 +1,141 @@
|
|
|
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-invalid-expo-config-value.ts
|
|
31
|
+
var no_invalid_expo_config_value_exports = {};
|
|
32
|
+
__export(no_invalid_expo_config_value_exports, {
|
|
33
|
+
default: () => no_invalid_expo_config_value_default
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(no_invalid_expo_config_value_exports);
|
|
36
|
+
var import_node_fs = __toESM(require("fs"));
|
|
37
|
+
var import_node_path2 = __toESM(require("path"));
|
|
38
|
+
|
|
39
|
+
// src/rules/utils.ts
|
|
40
|
+
var import_node_path = __toESM(require("path"));
|
|
41
|
+
var import_package_up = require("package-up");
|
|
42
|
+
function findProjectRoot(startPath) {
|
|
43
|
+
const pkgPath = (0, import_package_up.packageUpSync)({ cwd: import_node_path.default.dirname(startPath) });
|
|
44
|
+
return pkgPath ? import_node_path.default.dirname(pkgPath) : null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/rules/no-invalid-expo-config-value.ts
|
|
48
|
+
var USER_INTERFACE_STYLE = /* @__PURE__ */ new Set(["light", "dark", "automatic"]);
|
|
49
|
+
var ORIENTATION = /* @__PURE__ */ new Set(["default", "portrait", "landscape"]);
|
|
50
|
+
var SPLASH_RESIZE_MODE = /* @__PURE__ */ new Set(["contain", "cover"]);
|
|
51
|
+
var INITIAL_ORIENTATION = /* @__PURE__ */ new Set([
|
|
52
|
+
"DEFAULT",
|
|
53
|
+
"ALL",
|
|
54
|
+
"PORTRAIT",
|
|
55
|
+
"PORTRAIT_UP",
|
|
56
|
+
"PORTRAIT_DOWN",
|
|
57
|
+
"LANDSCAPE",
|
|
58
|
+
"LANDSCAPE_LEFT",
|
|
59
|
+
"LANDSCAPE_RIGHT"
|
|
60
|
+
]);
|
|
61
|
+
function collectEnumIssues(appJson) {
|
|
62
|
+
const issues = [];
|
|
63
|
+
const expo = appJson.expo ?? {};
|
|
64
|
+
const push = (field, value, allowed, allowedLabel) => {
|
|
65
|
+
if (typeof value === "string" && value.length > 0 && !allowed.has(value)) {
|
|
66
|
+
issues.push({ field, value, allowed: allowedLabel });
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
push("expo.orientation", expo.orientation, ORIENTATION, "default, portrait, landscape");
|
|
70
|
+
push("expo.userInterfaceStyle", expo.userInterfaceStyle, USER_INTERFACE_STYLE, "light, dark, automatic");
|
|
71
|
+
push(
|
|
72
|
+
"expo.android.userInterfaceStyle",
|
|
73
|
+
expo.android?.userInterfaceStyle,
|
|
74
|
+
USER_INTERFACE_STYLE,
|
|
75
|
+
"light, dark, automatic"
|
|
76
|
+
);
|
|
77
|
+
const splashes = [
|
|
78
|
+
["expo.splash", expo.splash],
|
|
79
|
+
["expo.android.splash", expo.android?.splash],
|
|
80
|
+
["expo.ios.splash", expo.ios?.splash]
|
|
81
|
+
];
|
|
82
|
+
for (const [prefix, splash] of splashes) {
|
|
83
|
+
if (!splash) continue;
|
|
84
|
+
push(`${prefix}.resizeMode`, splash.resizeMode, SPLASH_RESIZE_MODE, "contain, cover");
|
|
85
|
+
}
|
|
86
|
+
for (const entry of expo.plugins ?? []) {
|
|
87
|
+
if (!Array.isArray(entry) || entry[0] !== "expo-screen-orientation") continue;
|
|
88
|
+
const opts = entry[1];
|
|
89
|
+
if (opts != null && typeof opts === "object") {
|
|
90
|
+
const initial = opts.initialOrientation;
|
|
91
|
+
push(
|
|
92
|
+
"plugins[expo-screen-orientation].initialOrientation",
|
|
93
|
+
initial,
|
|
94
|
+
INITIAL_ORIENTATION,
|
|
95
|
+
"DEFAULT, ALL, PORTRAIT, PORTRAIT_UP, PORTRAIT_DOWN, LANDSCAPE, LANDSCAPE_LEFT, LANDSCAPE_RIGHT"
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return issues;
|
|
100
|
+
}
|
|
101
|
+
var noInvalidExpoConfigValueRule = {
|
|
102
|
+
meta: {
|
|
103
|
+
type: "problem",
|
|
104
|
+
docs: {
|
|
105
|
+
description: "Validate enum/string fields in app.json that `expo prebuild` consumes (userInterfaceStyle, orientation, splash.resizeMode, screen-orientation.initialOrientation)."
|
|
106
|
+
},
|
|
107
|
+
schema: [],
|
|
108
|
+
messages: {
|
|
109
|
+
invalidEnum: '{{field}} has invalid value "{{value}}". `expo prebuild` expects one of: {{allowed}}. Using an unrecognized value will either abort prebuild or be silently ignored.'
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
create(context) {
|
|
113
|
+
const projectRoot = findProjectRoot(context.filename);
|
|
114
|
+
if (!projectRoot) return {};
|
|
115
|
+
return {
|
|
116
|
+
Program(node) {
|
|
117
|
+
let appJson;
|
|
118
|
+
try {
|
|
119
|
+
appJson = JSON.parse(
|
|
120
|
+
import_node_fs.default.readFileSync(import_node_path2.default.join(projectRoot, "app.json"), "utf-8")
|
|
121
|
+
);
|
|
122
|
+
} catch {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
for (const issue of collectEnumIssues(appJson)) {
|
|
126
|
+
context.report({
|
|
127
|
+
node,
|
|
128
|
+
messageId: "invalidEnum",
|
|
129
|
+
data: { field: issue.field, value: issue.value, allowed: issue.allowed }
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
var plugin = {
|
|
137
|
+
meta: { name: "expo-config-value" },
|
|
138
|
+
rules: { "no-invalid-expo-config-value": noInvalidExpoConfigValueRule }
|
|
139
|
+
};
|
|
140
|
+
var no_invalid_expo_config_value_default = plugin;
|
|
141
|
+
module.exports = module.exports.default;
|
|
@@ -0,0 +1,228 @@
|
|
|
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-invalid-notification-config.ts
|
|
31
|
+
var no_invalid_notification_config_exports = {};
|
|
32
|
+
__export(no_invalid_notification_config_exports, {
|
|
33
|
+
default: () => no_invalid_notification_config_default
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(no_invalid_notification_config_exports);
|
|
36
|
+
var import_node_fs2 = __toESM(require("fs"));
|
|
37
|
+
var import_node_path2 = __toESM(require("path"));
|
|
38
|
+
|
|
39
|
+
// src/rules/utils.ts
|
|
40
|
+
var import_node_path = __toESM(require("path"));
|
|
41
|
+
var import_package_up = require("package-up");
|
|
42
|
+
function findProjectRoot(startPath) {
|
|
43
|
+
const pkgPath = (0, import_package_up.packageUpSync)({ cwd: import_node_path.default.dirname(startPath) });
|
|
44
|
+
return pkgPath ? import_node_path.default.dirname(pkgPath) : null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/rules/image-format.ts
|
|
48
|
+
var import_node_fs = __toESM(require("fs"));
|
|
49
|
+
var PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
50
|
+
var JPEG_SIGNATURE = Buffer.from([255, 216, 255]);
|
|
51
|
+
var GIF87_SIGNATURE = Buffer.from("GIF87a", "ascii");
|
|
52
|
+
var GIF89_SIGNATURE = Buffer.from("GIF89a", "ascii");
|
|
53
|
+
var RIFF_SIGNATURE = Buffer.from("RIFF", "ascii");
|
|
54
|
+
var WEBP_SIGNATURE = Buffer.from("WEBP", "ascii");
|
|
55
|
+
function detectImageFormat(filePath) {
|
|
56
|
+
let fd;
|
|
57
|
+
try {
|
|
58
|
+
fd = import_node_fs.default.openSync(filePath, "r");
|
|
59
|
+
} catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const buf = Buffer.alloc(12);
|
|
64
|
+
const bytesRead = import_node_fs.default.readSync(fd, buf, 0, buf.length, 0);
|
|
65
|
+
if (bytesRead >= 8 && buf.subarray(0, 8).equals(PNG_SIGNATURE)) {
|
|
66
|
+
return "png";
|
|
67
|
+
}
|
|
68
|
+
if (bytesRead >= 3 && buf.subarray(0, 3).equals(JPEG_SIGNATURE)) {
|
|
69
|
+
return "jpeg";
|
|
70
|
+
}
|
|
71
|
+
if (bytesRead >= 6 && (buf.subarray(0, 6).equals(GIF87_SIGNATURE) || buf.subarray(0, 6).equals(GIF89_SIGNATURE))) {
|
|
72
|
+
return "gif";
|
|
73
|
+
}
|
|
74
|
+
if (bytesRead >= 12 && buf.subarray(0, 4).equals(RIFF_SIGNATURE) && buf.subarray(8, 12).equals(WEBP_SIGNATURE)) {
|
|
75
|
+
return "webp";
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
} catch {
|
|
79
|
+
return null;
|
|
80
|
+
} finally {
|
|
81
|
+
import_node_fs.default.closeSync(fd);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/rules/no-invalid-notification-config.ts
|
|
86
|
+
var SUPPORTED_FORMATS = /* @__PURE__ */ new Set([
|
|
87
|
+
"png",
|
|
88
|
+
"jpeg",
|
|
89
|
+
"webp",
|
|
90
|
+
"gif"
|
|
91
|
+
]);
|
|
92
|
+
var EXT_TO_FORMAT = {
|
|
93
|
+
png: "png",
|
|
94
|
+
jpg: "jpeg",
|
|
95
|
+
jpeg: "jpeg",
|
|
96
|
+
jpe: "jpeg",
|
|
97
|
+
webp: "webp",
|
|
98
|
+
gif: "gif"
|
|
99
|
+
};
|
|
100
|
+
function isRemoteUrl(value) {
|
|
101
|
+
return value.startsWith("http://") || value.startsWith("https://");
|
|
102
|
+
}
|
|
103
|
+
var HEX_COLOR = /^#[0-9a-fA-F]{3}([0-9a-fA-F]{3}([0-9a-fA-F]{2})?)?$/;
|
|
104
|
+
function isHexColor(value) {
|
|
105
|
+
return HEX_COLOR.test(value);
|
|
106
|
+
}
|
|
107
|
+
function looksLikeColorName(value) {
|
|
108
|
+
if (!/^[a-z][a-z0-9_]*$/i.test(value) || value.includes(" ")) return false;
|
|
109
|
+
return !/^[0-9a-f]+$/i.test(value);
|
|
110
|
+
}
|
|
111
|
+
function getNotificationPluginOptions(plugins) {
|
|
112
|
+
for (const entry of plugins) {
|
|
113
|
+
if (entry === "expo-notifications") return {};
|
|
114
|
+
if (Array.isArray(entry) && entry[0] === "expo-notifications") {
|
|
115
|
+
const opts = entry[1];
|
|
116
|
+
if (opts != null && typeof opts === "object") return opts;
|
|
117
|
+
return {};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
function checkIcon(projectRoot, icon) {
|
|
123
|
+
if (typeof icon !== "string") return null;
|
|
124
|
+
if (isRemoteUrl(icon)) return null;
|
|
125
|
+
const abs = import_node_path2.default.resolve(projectRoot, icon);
|
|
126
|
+
if (!import_node_fs2.default.existsSync(abs)) return { kind: "iconMissing" };
|
|
127
|
+
const ext = import_node_path2.default.extname(icon).replace(/^\./, "").toLowerCase();
|
|
128
|
+
const declared = EXT_TO_FORMAT[ext];
|
|
129
|
+
if (!declared) {
|
|
130
|
+
return { kind: "iconUnsupported", format: ext || "unknown" };
|
|
131
|
+
}
|
|
132
|
+
const actual = detectImageFormat(abs);
|
|
133
|
+
if (actual === null || !SUPPORTED_FORMATS.has(actual)) {
|
|
134
|
+
return { kind: "iconUnsupported", format: actual ?? "unknown" };
|
|
135
|
+
}
|
|
136
|
+
if (declared !== actual) {
|
|
137
|
+
return { kind: "iconMasquerade", declared, actual };
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
function collectIssues(projectRoot, options) {
|
|
142
|
+
const issues = [];
|
|
143
|
+
if (options.sounds !== void 0 && options.sounds !== null) {
|
|
144
|
+
if (!Array.isArray(options.sounds) && typeof options.sounds !== "string") {
|
|
145
|
+
issues.push({ kind: "soundsNotArray", actualType: typeof options.sounds });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (typeof options.color === "string" && options.color.length > 0) {
|
|
149
|
+
if (!isHexColor(options.color) && !looksLikeColorName(options.color)) {
|
|
150
|
+
issues.push({ kind: "invalidColor", value: options.color });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (options.icon !== void 0 && options.icon !== null) {
|
|
154
|
+
const iconIssue = checkIcon(projectRoot, options.icon);
|
|
155
|
+
if (iconIssue) issues.push(iconIssue);
|
|
156
|
+
}
|
|
157
|
+
return issues;
|
|
158
|
+
}
|
|
159
|
+
var noInvalidNotificationConfigRule = {
|
|
160
|
+
meta: {
|
|
161
|
+
type: "problem",
|
|
162
|
+
docs: {
|
|
163
|
+
description: "Validate expo-notifications plugin config: sounds must be an array, color must be a valid hex/name, icon must be a supported image format and not masquerading."
|
|
164
|
+
},
|
|
165
|
+
schema: [],
|
|
166
|
+
messages: {
|
|
167
|
+
soundsNotArray: 'expo-notifications `sounds` must be an array of file paths, found {{actualType}}. `expo prebuild` throws: "Must provide an array of sound files in your app config".',
|
|
168
|
+
invalidColor: 'expo-notifications `color` "{{value}}" is not a valid color. Use a hex color like "#E63946" (supports #RGB / #RRGGBB / #AARRGGBB) or a lowercase color name.',
|
|
169
|
+
iconMissing: "expo-notifications `icon` references a file that does not exist.",
|
|
170
|
+
iconUnsupported: 'expo-notifications `icon` has unsupported image format "{{format}}". `expo prebuild` (via @expo/image-utils) only supports png, jpeg, webp, gif.',
|
|
171
|
+
iconMasquerade: "expo-notifications `icon` is declared as .{{declared}} but the file content is actually {{actual}}. This format masquerade fails prebuild. Convert the file to match its extension."
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
create(context) {
|
|
175
|
+
const projectRoot = findProjectRoot(context.filename);
|
|
176
|
+
if (!projectRoot) return {};
|
|
177
|
+
return {
|
|
178
|
+
Program(node) {
|
|
179
|
+
let appJson;
|
|
180
|
+
try {
|
|
181
|
+
appJson = JSON.parse(
|
|
182
|
+
import_node_fs2.default.readFileSync(import_node_path2.default.join(projectRoot, "app.json"), "utf-8")
|
|
183
|
+
);
|
|
184
|
+
} catch {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const plugins = appJson.expo?.plugins ?? [];
|
|
188
|
+
const options = getNotificationPluginOptions(plugins);
|
|
189
|
+
if (!options) return;
|
|
190
|
+
for (const issue of collectIssues(projectRoot, options)) {
|
|
191
|
+
if (issue.kind === "soundsNotArray") {
|
|
192
|
+
context.report({
|
|
193
|
+
node,
|
|
194
|
+
messageId: "soundsNotArray",
|
|
195
|
+
data: { actualType: issue.actualType }
|
|
196
|
+
});
|
|
197
|
+
} else if (issue.kind === "invalidColor") {
|
|
198
|
+
context.report({
|
|
199
|
+
node,
|
|
200
|
+
messageId: "invalidColor",
|
|
201
|
+
data: { value: issue.value }
|
|
202
|
+
});
|
|
203
|
+
} else if (issue.kind === "iconMissing") {
|
|
204
|
+
context.report({ node, messageId: "iconMissing" });
|
|
205
|
+
} else if (issue.kind === "iconUnsupported") {
|
|
206
|
+
context.report({
|
|
207
|
+
node,
|
|
208
|
+
messageId: "iconUnsupported",
|
|
209
|
+
data: { format: issue.format }
|
|
210
|
+
});
|
|
211
|
+
} else {
|
|
212
|
+
context.report({
|
|
213
|
+
node,
|
|
214
|
+
messageId: "iconMasquerade",
|
|
215
|
+
data: { declared: issue.declared, actual: issue.actual }
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
var plugin = {
|
|
224
|
+
meta: { name: "expo-notifications-config" },
|
|
225
|
+
rules: { "no-invalid-notification-config": noInvalidNotificationConfigRule }
|
|
226
|
+
};
|
|
227
|
+
var no_invalid_notification_config_default = plugin;
|
|
228
|
+
module.exports = module.exports.default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "miaoda-expo-devkit",
|
|
3
|
-
"version": "0.1.1-beta.
|
|
3
|
+
"version": "0.1.1-beta.97",
|
|
4
4
|
"description": "Expo 应用开发工具集:Sentry DSN 替换 stub、错误/网络捕获、Metro 符号化",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -64,6 +64,8 @@
|
|
|
64
64
|
"./rules/no-missing-image-import": "./dist/rules/no-missing-image-import.js",
|
|
65
65
|
"./rules/no-splash-screen-missing-image": "./dist/rules/no-splash-screen-missing-image.js",
|
|
66
66
|
"./rules/no-missing-notification-asset": "./dist/rules/no-missing-notification-asset.js",
|
|
67
|
+
"./rules/no-invalid-notification-config": "./dist/rules/no-invalid-notification-config.js",
|
|
68
|
+
"./rules/no-invalid-expo-config-value": "./dist/rules/no-invalid-expo-config-value.js",
|
|
67
69
|
"./rules/no-gifted-charts-missing-linear-gradient": "./dist/rules/no-gifted-charts-missing-linear-gradient.js",
|
|
68
70
|
"./biome": "./biome-config.json",
|
|
69
71
|
"./oxlint": "./oxlint-config.json",
|