@serveryyswys/opm 0.1.1 → 0.1.2

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.
@@ -8,8 +8,15 @@
8
8
  * 以及 "// require('x')" 这种情况。
9
9
  */
10
10
  export interface RequireSite {
11
- /** require 的实参(已去引号、已解转义) */
12
- spec: string;
11
+ /** require 的实参(已去引号、已解转义);**动态形式为 null** */
12
+ spec: string | null;
13
+ /**
14
+ * 无法静态分析(变量 / 模板串 / 字符串拼接 / 三元…)。
15
+ *
16
+ * 这类 require 打包器改不了,而 Operit 运行时对裸名**静默返回 {}** ——
17
+ * 于是依赖在业务里神秘失效。所以必须显式报错,不能放过。
18
+ */
19
+ dynamic: boolean;
13
20
  /** spec 在源码里的起止下标(不含引号),替换时用 */
14
21
  start: number;
15
22
  end: number;
@@ -97,12 +97,29 @@ function findRequires(source) {
97
97
  cursor += 1;
98
98
  }
99
99
  if (cursor < length) {
100
- sites.push({ spec: value, start: start, end: cursor });
100
+ // 字面量后面若还跟着运算('a' + x / 'a' ? ...),实参其实是表达式。
101
+ // 以前这里会把它当成 'a' 去重写 —— 截断比忽略更糟,必须区分。
102
+ let after = cursor + 1;
103
+ while (after < length && /\s/.test(source[after])) {
104
+ after += 1;
105
+ }
106
+ const trailing = source[after];
107
+ const isExpression = trailing === '+' || trailing === '?' || trailing === '|' || trailing === '&';
108
+ sites.push({
109
+ spec: isExpression ? null : value,
110
+ dynamic: isExpression,
111
+ start: start,
112
+ end: cursor
113
+ });
101
114
  index = cursor + 1;
102
115
  previousMeaningful = quote;
103
116
  continue;
104
117
  }
105
118
  }
119
+ else {
120
+ // 实参不是字符串字面量:变量 / 模板串 / 三元 / 函数调用…全部无法静态改写
121
+ sites.push({ spec: null, dynamic: true, start: cursor, end: cursor });
122
+ }
106
123
  }
107
124
  }
108
125
  }
@@ -150,6 +150,14 @@ function rewriteModule(env, archivePath, source) {
150
150
  let output = source;
151
151
  for (let index = sites.length - 1; index >= 0; index -= 1) {
152
152
  const site = sites[index];
153
+ if (site.dynamic) {
154
+ // 改不了就必须说,不能默认放过:运行时对裸名静默返回 {},
155
+ // 症状会是"某个依赖神秘失效",比构建立刻失败难查得多。
156
+ errors.push(archivePath + ' 里存在无法静态分析的 require(偏移 ' + site.start + ')。\n' +
157
+ ' 打包器无法改写它,而 Operit 运行时对裸名会静默返回 {} —— 依赖会在业务里失效而不报错。\n' +
158
+ ' 请改成字符串字面量(require(\'fs\')),或拆成多分支的字面量 require。');
159
+ continue;
160
+ }
153
161
  const spec = site.spec;
154
162
  if (contract_1.RUNTIME_BUILTINS.includes(spec)) {
155
163
  diagnostics.push({ file: archivePath, spec, kind: 'untouched', target: spec });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serveryyswys/opm",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "把 Operit 插件工程打成 .toolpkg 的构建器(传统 Node 开发环境,不依赖 Operit 运行时)",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "serveryyswys",