web 3d图形渲染器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

403 lines
11 KiB

  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var t = require('@babel/types');
  4. function willPathCastToBoolean(path) {
  5. const maybeWrapped = path;
  6. const {
  7. node,
  8. parentPath
  9. } = maybeWrapped;
  10. if (parentPath.isLogicalExpression()) {
  11. const {
  12. operator,
  13. right
  14. } = parentPath.node;
  15. if (operator === "&&" || operator === "||" || operator === "??" && node === right) {
  16. return willPathCastToBoolean(parentPath);
  17. }
  18. }
  19. if (parentPath.isSequenceExpression()) {
  20. const {
  21. expressions
  22. } = parentPath.node;
  23. if (expressions[expressions.length - 1] === node) {
  24. return willPathCastToBoolean(parentPath);
  25. } else {
  26. return true;
  27. }
  28. }
  29. return parentPath.isConditional({
  30. test: node
  31. }) || parentPath.isUnaryExpression({
  32. operator: "!"
  33. }) || parentPath.isLoop({
  34. test: node
  35. });
  36. }
  37. class AssignmentMemoiser {
  38. constructor() {
  39. this._map = void 0;
  40. this._map = new WeakMap();
  41. }
  42. has(key) {
  43. return this._map.has(key);
  44. }
  45. get(key) {
  46. if (!this.has(key)) return;
  47. const record = this._map.get(key);
  48. const {
  49. value
  50. } = record;
  51. record.count--;
  52. if (record.count === 0) {
  53. return t.assignmentExpression("=", value, key);
  54. }
  55. return value;
  56. }
  57. set(key, value, count) {
  58. return this._map.set(key, {
  59. count,
  60. value
  61. });
  62. }
  63. }
  64. function toNonOptional(path, base) {
  65. const {
  66. node
  67. } = path;
  68. if (path.isOptionalMemberExpression()) {
  69. return t.memberExpression(base, node.property, node.computed);
  70. }
  71. if (path.isOptionalCallExpression()) {
  72. const callee = path.get("callee");
  73. if (path.node.optional && callee.isOptionalMemberExpression()) {
  74. const {
  75. object
  76. } = callee.node;
  77. const context = path.scope.maybeGenerateMemoised(object) || object;
  78. callee.get("object").replaceWith(t.assignmentExpression("=", context, object));
  79. return t.callExpression(t.memberExpression(base, t.identifier("call")), [context, ...node.arguments]);
  80. }
  81. return t.callExpression(base, node.arguments);
  82. }
  83. return path.node;
  84. }
  85. function isInDetachedTree(path) {
  86. while (path) {
  87. if (path.isProgram()) break;
  88. const {
  89. parentPath,
  90. container,
  91. listKey
  92. } = path;
  93. const parentNode = parentPath.node;
  94. if (listKey) {
  95. if (container !== parentNode[listKey]) return true;
  96. } else {
  97. if (container !== parentNode) return true;
  98. }
  99. path = parentPath;
  100. }
  101. return false;
  102. }
  103. const handle = {
  104. memoise() {},
  105. handle(member, noDocumentAll) {
  106. const {
  107. node,
  108. parent,
  109. parentPath,
  110. scope
  111. } = member;
  112. if (member.isOptionalMemberExpression()) {
  113. if (isInDetachedTree(member)) return;
  114. const endPath = member.find(({
  115. node,
  116. parent,
  117. parentPath
  118. }) => {
  119. if (parentPath.isOptionalMemberExpression()) {
  120. return parent.optional || parent.object !== node;
  121. }
  122. if (parentPath.isOptionalCallExpression()) {
  123. return node !== member.node && parent.optional || parent.callee !== node;
  124. }
  125. return true;
  126. });
  127. if (scope.path.isPattern()) {
  128. endPath.replaceWith(t.callExpression(t.arrowFunctionExpression([], endPath.node), []));
  129. return;
  130. }
  131. const willEndPathCastToBoolean = willPathCastToBoolean(endPath);
  132. const rootParentPath = endPath.parentPath;
  133. if (rootParentPath.isUpdateExpression({
  134. argument: node
  135. }) || rootParentPath.isAssignmentExpression({
  136. left: node
  137. })) {
  138. throw member.buildCodeFrameError(`can't handle assignment`);
  139. }
  140. const isDeleteOperation = rootParentPath.isUnaryExpression({
  141. operator: "delete"
  142. });
  143. if (isDeleteOperation && endPath.isOptionalMemberExpression() && endPath.get("property").isPrivateName()) {
  144. throw member.buildCodeFrameError(`can't delete a private class element`);
  145. }
  146. let startingOptional = member;
  147. for (;;) {
  148. if (startingOptional.isOptionalMemberExpression()) {
  149. if (startingOptional.node.optional) break;
  150. startingOptional = startingOptional.get("object");
  151. continue;
  152. } else if (startingOptional.isOptionalCallExpression()) {
  153. if (startingOptional.node.optional) break;
  154. startingOptional = startingOptional.get("callee");
  155. continue;
  156. }
  157. throw new Error(`Internal error: unexpected ${startingOptional.node.type}`);
  158. }
  159. const startingProp = startingOptional.isOptionalMemberExpression() ? "object" : "callee";
  160. const startingNode = startingOptional.node[startingProp];
  161. const baseNeedsMemoised = scope.maybeGenerateMemoised(startingNode);
  162. const baseRef = baseNeedsMemoised != null ? baseNeedsMemoised : startingNode;
  163. const parentIsOptionalCall = parentPath.isOptionalCallExpression({
  164. callee: node
  165. });
  166. const parentIsCall = parentPath.isCallExpression({
  167. callee: node
  168. });
  169. startingOptional.replaceWith(toNonOptional(startingOptional, baseRef));
  170. if (parentIsOptionalCall) {
  171. if (parent.optional) {
  172. parentPath.replaceWith(this.optionalCall(member, parent.arguments));
  173. } else {
  174. parentPath.replaceWith(this.call(member, parent.arguments));
  175. }
  176. } else if (parentIsCall) {
  177. member.replaceWith(this.boundGet(member));
  178. } else {
  179. member.replaceWith(this.get(member));
  180. }
  181. let regular = member.node;
  182. for (let current = member; current !== endPath;) {
  183. const {
  184. parentPath
  185. } = current;
  186. if (parentPath === endPath && parentIsOptionalCall && parent.optional) {
  187. regular = parentPath.node;
  188. break;
  189. }
  190. regular = toNonOptional(parentPath, regular);
  191. current = parentPath;
  192. }
  193. let context;
  194. const endParentPath = endPath.parentPath;
  195. if (t.isMemberExpression(regular) && endParentPath.isOptionalCallExpression({
  196. callee: endPath.node,
  197. optional: true
  198. })) {
  199. const {
  200. object
  201. } = regular;
  202. context = member.scope.maybeGenerateMemoised(object);
  203. if (context) {
  204. regular.object = t.assignmentExpression("=", context, object);
  205. }
  206. }
  207. let replacementPath = endPath;
  208. if (isDeleteOperation) {
  209. replacementPath = endParentPath;
  210. regular = endParentPath.node;
  211. }
  212. const baseMemoised = baseNeedsMemoised ? t.assignmentExpression("=", t.cloneNode(baseRef), t.cloneNode(startingNode)) : t.cloneNode(baseRef);
  213. if (willEndPathCastToBoolean) {
  214. let nonNullishCheck;
  215. if (noDocumentAll) {
  216. nonNullishCheck = t.binaryExpression("!=", baseMemoised, t.nullLiteral());
  217. } else {
  218. nonNullishCheck = t.logicalExpression("&&", t.binaryExpression("!==", baseMemoised, t.nullLiteral()), t.binaryExpression("!==", t.cloneNode(baseRef), scope.buildUndefinedNode()));
  219. }
  220. replacementPath.replaceWith(t.logicalExpression("&&", nonNullishCheck, regular));
  221. } else {
  222. let nullishCheck;
  223. if (noDocumentAll) {
  224. nullishCheck = t.binaryExpression("==", baseMemoised, t.nullLiteral());
  225. } else {
  226. nullishCheck = t.logicalExpression("||", t.binaryExpression("===", baseMemoised, t.nullLiteral()), t.binaryExpression("===", t.cloneNode(baseRef), scope.buildUndefinedNode()));
  227. }
  228. replacementPath.replaceWith(t.conditionalExpression(nullishCheck, isDeleteOperation ? t.booleanLiteral(true) : scope.buildUndefinedNode(), regular));
  229. }
  230. if (context) {
  231. const endParent = endParentPath.node;
  232. endParentPath.replaceWith(t.optionalCallExpression(t.optionalMemberExpression(endParent.callee, t.identifier("call"), false, true), [t.cloneNode(context), ...endParent.arguments], false));
  233. }
  234. return;
  235. }
  236. if (parentPath.isUpdateExpression({
  237. argument: node
  238. })) {
  239. if (this.simpleSet) {
  240. member.replaceWith(this.simpleSet(member));
  241. return;
  242. }
  243. const {
  244. operator,
  245. prefix
  246. } = parent;
  247. this.memoise(member, 2);
  248. const value = t.binaryExpression(operator[0], t.unaryExpression("+", this.get(member)), t.numericLiteral(1));
  249. if (prefix) {
  250. parentPath.replaceWith(this.set(member, value));
  251. } else {
  252. const {
  253. scope
  254. } = member;
  255. const ref = scope.generateUidIdentifierBasedOnNode(node);
  256. scope.push({
  257. id: ref
  258. });
  259. value.left = t.assignmentExpression("=", t.cloneNode(ref), value.left);
  260. parentPath.replaceWith(t.sequenceExpression([this.set(member, value), t.cloneNode(ref)]));
  261. }
  262. return;
  263. }
  264. if (parentPath.isAssignmentExpression({
  265. left: node
  266. })) {
  267. if (this.simpleSet) {
  268. member.replaceWith(this.simpleSet(member));
  269. return;
  270. }
  271. const {
  272. operator,
  273. right: value
  274. } = parent;
  275. if (operator === "=") {
  276. parentPath.replaceWith(this.set(member, value));
  277. } else {
  278. const operatorTrunc = operator.slice(0, -1);
  279. if (t.LOGICAL_OPERATORS.includes(operatorTrunc)) {
  280. this.memoise(member, 1);
  281. parentPath.replaceWith(t.logicalExpression(operatorTrunc, this.get(member), this.set(member, value)));
  282. } else {
  283. this.memoise(member, 2);
  284. parentPath.replaceWith(this.set(member, t.binaryExpression(operatorTrunc, this.get(member), value)));
  285. }
  286. }
  287. return;
  288. }
  289. if (parentPath.isCallExpression({
  290. callee: node
  291. })) {
  292. parentPath.replaceWith(this.call(member, parent.arguments));
  293. return;
  294. }
  295. if (parentPath.isOptionalCallExpression({
  296. callee: node
  297. })) {
  298. if (scope.path.isPattern()) {
  299. parentPath.replaceWith(t.callExpression(t.arrowFunctionExpression([], parentPath.node), []));
  300. return;
  301. }
  302. parentPath.replaceWith(this.optionalCall(member, parent.arguments));
  303. return;
  304. }
  305. if (parentPath.isForXStatement({
  306. left: node
  307. }) || parentPath.isObjectProperty({
  308. value: node
  309. }) && parentPath.parentPath.isObjectPattern() || parentPath.isAssignmentPattern({
  310. left: node
  311. }) && parentPath.parentPath.isObjectProperty({
  312. value: parent
  313. }) && parentPath.parentPath.parentPath.isObjectPattern() || parentPath.isArrayPattern() || parentPath.isAssignmentPattern({
  314. left: node
  315. }) && parentPath.parentPath.isArrayPattern() || parentPath.isRestElement()) {
  316. member.replaceWith(this.destructureSet(member));
  317. return;
  318. }
  319. member.replaceWith(this.get(member));
  320. }
  321. };
  322. function memberExpressionToFunctions(path, visitor, state) {
  323. path.traverse(visitor, Object.assign({}, handle, state, {
  324. memoiser: new AssignmentMemoiser()
  325. }));
  326. }
  327. exports.default = memberExpressionToFunctions;
  328. //# sourceMappingURL=index.js.map