Skip to content

Commit

Permalink
[wip] Implement transform support for using declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed May 17, 2023
1 parent 500e298 commit 52ce528
Show file tree
Hide file tree
Showing 30 changed files with 424 additions and 0 deletions.
8 changes: 8 additions & 0 deletions packages/babel-helpers/src/helpers-generated.ts
Expand Up @@ -57,6 +57,10 @@ export default Object.freeze({
"7.20.7",
"export default function _defineAccessor(type,obj,key,fn){var desc={configurable:!0,enumerable:!0};return desc[type]=fn,Object.defineProperty(obj,key,desc)}",
),
dispose: helper(
"7.0.0-beta.0",
"function dispose_SuppressedError(suppressed,error){return dispose_SuppressedError=function(suppressed,error){this.suppressed=suppressed,this.error=error,this.stack=(new Error).stack},dispose_SuppressedError.prototype=Object.create(Error.prototype,{constructor:{value:dispose_SuppressedError,writable:!0,configurable:!0}}),new dispose_SuppressedError(suppressed,error)}export default function _dispose(stack,error,hasError,SuppressedError){for(;stack.length>0;){const r=stack.pop();try{r.d.call(r.v)}catch(e){error=hasError?new(SuppressedError||dispose_SuppressedError)(e,error):e,hasError=!0}}if(hasError)throw error}",
),
iterableToArrayLimit: helper(
"7.0.0-beta.0",
'export default function _iterableToArrayLimit(arr,i){var _i=null==arr?null:"undefined"!=typeof Symbol&&arr[Symbol.iterator]||arr["@@iterator"];if(null!=_i){var _s,_e,_x,_r,_arr=[],_n=!0,_d=!1;try{if(_x=(_i=_i.call(arr)).next,0===i){if(Object(_i)!==_i)return;_n=!1}else for(;!(_n=(_s=_x.call(_i)).done)&&(_arr.push(_s.value),_arr.length!==i);_n=!0);}catch(err){_d=!0,_e=err}finally{try{if(!_n&&null!=_i.return&&(_r=_i.return(),Object(_r)!==_r))return}finally{if(_d)throw _e}}return _arr}}',
Expand All @@ -81,6 +85,10 @@ export default Object.freeze({
"7.0.0-beta.0",
'export default function _typeof(obj){"@babel/helpers - typeof";return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(obj){return typeof obj}:function(obj){return obj&&"function"==typeof Symbol&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj},_typeof(obj)}',
),
using: helper(
"7.0.0-beta.0",
'export default function _using(stack,value){if(null!=value){var dispose=value[Symbol.dispose||Symbol.for("Symbol.dispose")];if("function"!=typeof dispose)throw new TypeError("Property [Symbol.dispose] is not a function.");stack.push({v:value,d:dispose})}return value}',
),
wrapRegExp: helper(
"7.19.0",
'import setPrototypeOf from"setPrototypeOf";import inherits from"inherits";export default function _wrapRegExp(){_wrapRegExp=function(re,groups){return new BabelRegExp(re,void 0,groups)};var _super=RegExp.prototype,_groups=new WeakMap;function BabelRegExp(re,flags,groups){var _this=new RegExp(re,flags);return _groups.set(_this,groups||_groups.get(re)),setPrototypeOf(_this,BabelRegExp.prototype)}function buildGroups(result,re){var g=_groups.get(re);return Object.keys(g).reduce((function(groups,name){var i=g[name];if("number"==typeof i)groups[name]=result[i];else{for(var k=0;void 0===result[i[k]]&&k+1<i.length;)k++;groups[name]=result[i[k]]}return groups}),Object.create(null))}return inherits(BabelRegExp,RegExp),BabelRegExp.prototype.exec=function(str){var result=_super.exec.call(this,str);if(result){result.groups=buildGroups(result,this);var indices=result.indices;indices&&(indices.groups=buildGroups(indices,this))}return result},BabelRegExp.prototype[Symbol.replace]=function(str,substitution){if("string"==typeof substitution){var groups=_groups.get(this);return _super[Symbol.replace].call(this,str,substitution.replace(/\\$<([^>]+)>/g,(function(_,name){var group=groups[name];return"$"+(Array.isArray(group)?group.join("$"):group)})))}if("function"==typeof substitution){var _this=this;return _super[Symbol.replace].call(this,str,(function(){var args=arguments;return"object"!=typeof args[args.length-1]&&(args=[].slice.call(args)).push(buildGroups(args,_this)),substitution.apply(this,args)}))}return _super[Symbol.replace].call(this,str,substitution)},_wrapRegExp.apply(this,arguments)}',
Expand Down
31 changes: 31 additions & 0 deletions packages/babel-helpers/src/helpers/dispose.js
@@ -0,0 +1,31 @@
/* @minVersion 7.0.0-beta.0 */
function dispose_SuppressedError(suppressed, error) {
dispose_SuppressedError = function SuppressedError(suppressed, error) {
this.suppressed = suppressed;
this.error = error;
this.stack = new Error().stack;
};
dispose_SuppressedError.prototype = Object.create(Error.prototype, {
constructor: {
value: dispose_SuppressedError,
writable: true,
configurable: true,
},
});
return new dispose_SuppressedError(suppressed, error);
}

export default function _dispose(stack, error, hasError, SuppressedError) {
while (stack.length > 0) {
const r = stack.pop();
try {
r.d.call(r.v);
} catch (e) {
error = hasError
? new (SuppressedError || dispose_SuppressedError)(e, error)
: e;
hasError = true;
}
}
if (hasError) throw error;
}
13 changes: 13 additions & 0 deletions packages/babel-helpers/src/helpers/using.js
@@ -0,0 +1,13 @@
/* @minVersion 7.0.0-beta.0 */

export default function _using(stack, value) {
if (value !== null && value !== void 0) {
// core-js-pure uses Symbol.for("Symbol.dispose").
var dispose = value[Symbol.dispose || Symbol.for("Symbol.dispose")];
if (typeof dispose !== "function") {
throw new TypeError(`Property [Symbol.dispose] is not a function.`);
}
stack.push({ v: value, d: dispose });
}
return value;
}
@@ -0,0 +1,3 @@
src
test
*.log
@@ -0,0 +1,19 @@
# @babel/plugin-proposal-explicit-resource-managements

> Compile `using` declarations to ES2015
See our website [@babel/plugin-proposal-explicit-resource-managements](https://babeljs.io/docs/en/babel-plugin-proposal-explicit-resource-managements) for more information.

## Install

Using npm:

```sh
npm install --save-dev @babel/plugin-proposal-explicit-resource-managements
```

or using yarn:

```sh
yarn add @babel/plugin-proposal-explicit-resource-managements --dev
```
@@ -0,0 +1,47 @@
{
"name": "@babel/plugin-proposal-explicit-resource-management",
"version": "7.18.6",
"description": "Compile `using` declarations to ES2015",
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-plugin-proposal-explicit-resource-management"
},
"homepage": "https://babel.dev/docs/en/next/babel-plugin-proposal-explicit-resource-management",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "./lib/index.js",
"keywords": [
"babel-plugin"
],
"dependencies": {
"@babel/helper-plugin-utils": "workspace:^",
"@babel/plugin-syntax-explicit-resource-management": "workspace:^"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
},
"devDependencies": {
"@babel/core": "workspace:^",
"@babel/helper-plugin-test-runner": "workspace:^"
},
"engines": {
"node": ">=6.9.0"
},
"author": "The Babel Team (https://babel.dev/team)",
"conditions": {
"USE_ESM": [
{
"type": "module"
},
null
]
},
"exports": {
".": "./lib/index.js",
"./package.json": "./package.json"
},
"type": "commonjs"
}
@@ -0,0 +1,85 @@
import { declare } from "@babel/helper-plugin-utils";
import syntacExplicitResourceManagement from "@babel/plugin-syntax-explicit-resource-management";
import { types as t, template } from "@babel/core";
import type { NodePath } from "@babel/traverse";

export default declare(api => {
// TOOD: assert version 7.22.0
api.assertVersion(7);

return {
name: "proposal-explicit-resource-management",
inherits: syntacExplicitResourceManagement,

visitor: {
VariableDeclaration(path) {
if (path.node.kind === "using") {
throw path.buildCodeFrameError(
`"using" declaration at the top-level of modules is not supported yet.`,
);
}
},
ForOfStatement(path: NodePath<t.ForOfStatement>) {
const { left } = path.node;
if (!t.isVariableDeclaration(left, { kind: "using" })) return;

const { id } = left.declarations[0];
const tmpId = path.scope.generateUidIdentifierBasedOnNode(id);
left.declarations[0].id = tmpId;
left.kind = "const";

path.ensureBlock();
path.node.body.body.unshift(
t.variableDeclaration("using", [
t.variableDeclarator(id, t.cloneNode(tmpId)),
]),
);
},
BlockStatement(path, state) {
let stackId: t.Identifier | null = null;
for (const node of path.node.body) {
if (!t.isVariableDeclaration(node, { kind: "using" })) continue;
node.kind = "const";
stackId ??= path.scope.generateUidIdentifier("stack");

node.declarations.forEach(decl => {
decl.init = t.callExpression(state.addHelper("using"), [
t.cloneNode(stackId),
decl.init,
]);
});
}
if (!stackId) return;

const errorId = path.scope.generateUidIdentifier("error");
const hasErrorId = path.scope.generateUidIdentifier("hasError");

const replacement = template.statement.ast`
try {
var ${stackId} = [];
${path.node.body}
} catch (_) {
var ${errorId} = _;
var ${hasErrorId} = true;
} finally {
${state.addHelper("dispose")}(
${t.cloneNode(stackId)},
${t.cloneNode(errorId)},
${t.cloneNode(hasErrorId)},
// Pass SuppressedError so that it can be used with "pure"
// polyfills that do not compile the contents of runtime
// helpers.
typeof SuppressedError !== undefined && SuppressedError
);
}
`;

if (path.parentPath.isFunction()) {
path.replaceWith(t.blockStatement([replacement]));
} else {
path.replaceWith(replacement);
}
},
},
};
});
@@ -0,0 +1,3 @@
{
"plugins": ["proposal-explicit-resource-management"]
}
@@ -0,0 +1,4 @@
{
using x = obj;
doSomethingWith(x);
}
@@ -0,0 +1,10 @@
try {
var _stack = [];
const x = babelHelpers.using(_stack, obj);
doSomethingWith(x);
} catch (_) {
var _error = _;
var _hasError = true;
} finally {
babelHelpers.dispose(_stack, _error, _hasError, typeof SuppressedError !== undefined && SuppressedError);
}
@@ -0,0 +1,3 @@
for await (using x of y) {
doSomethingWith(x);
}
@@ -0,0 +1,3 @@
{
"sourceType": "module"
}
@@ -0,0 +1,10 @@
for await (const _x of y) try {
var _stack = [];
const x = babelHelpers.using(_stack, _x);
doSomethingWith(x);
} catch (_) {
var _error = _;
var _hasError = true;
} finally {
babelHelpers.dispose(_stack, _error, _hasError, typeof SuppressedError !== undefined && SuppressedError);
}
@@ -0,0 +1,3 @@
for (using x of y) {
doSomethingWith(x);
}
@@ -0,0 +1,10 @@
for (const _x of y) try {
var _stack = [];
const x = babelHelpers.using(_stack, _x);
doSomethingWith(x);
} catch (_) {
var _error = _;
var _hasError = true;
} finally {
babelHelpers.dispose(_stack, _error, _hasError, typeof SuppressedError !== undefined && SuppressedError);
}
@@ -0,0 +1,4 @@
if (test) {
using x = obj;
doSomethingWith(x);
}
@@ -0,0 +1,10 @@
if (test) try {
var _stack = [];
const x = babelHelpers.using(_stack, obj);
doSomethingWith(x);
} catch (_) {
var _error = _;
var _hasError = true;
} finally {
babelHelpers.dispose(_stack, _error, _hasError, typeof SuppressedError !== undefined && SuppressedError);
}
@@ -0,0 +1,4 @@
function fn() {
using x = obj;
return doSomethingWith(x);
}
@@ -0,0 +1,12 @@
function fn() {
try {
var _stack = [];
const x = babelHelpers.using(_stack, obj);
return doSomethingWith(x);
} catch (_) {
var _error = _;
var _hasError = true;
} finally {
babelHelpers.dispose(_stack, _error, _hasError, typeof SuppressedError !== undefined && SuppressedError);
}
}
@@ -0,0 +1,11 @@
{
using x = obj;
{
using y = call(() => {
using z = obj;
return z;
});
stmt;
}
stmt;
}
@@ -0,0 +1,31 @@
try {
var _stack = [];
const x = babelHelpers.using(_stack, obj);
try {
var _stack2 = [];
const y = babelHelpers.using(_stack2, call(() => {
try {
var _stack3 = [];
const z = babelHelpers.using(_stack3, obj);
return z;
} catch (_) {
var _error3 = _;
var _hasError3 = true;
} finally {
babelHelpers.dispose(_stack3, _error3, _hasError3, typeof SuppressedError !== undefined && SuppressedError);
}
}));
stmt;
} catch (_) {
var _error2 = _;
var _hasError2 = true;
} finally {
babelHelpers.dispose(_stack2, _error2, _hasError2, typeof SuppressedError !== undefined && SuppressedError);
}
stmt;
} catch (_) {
var _error = _;
var _hasError = true;
} finally {
babelHelpers.dispose(_stack, _error, _hasError, typeof SuppressedError !== undefined && SuppressedError);
}
@@ -0,0 +1,9 @@
{
stmt;
using x = obj;
stmt;
using y = obj, z = obj;
stmt;
using w = obj;
doSomethingWith(x, z);
}
@@ -0,0 +1,16 @@
try {
var _stack = [];
stmt;
const x = babelHelpers.using(_stack, obj);
stmt;
const y = babelHelpers.using(_stack, obj),
z = babelHelpers.using(_stack, obj);
stmt;
const w = babelHelpers.using(_stack, obj);
doSomethingWith(x, z);
} catch (_) {
var _error = _;
var _hasError = true;
} finally {
babelHelpers.dispose(_stack, _error, _hasError, typeof SuppressedError !== undefined && SuppressedError);
}
@@ -0,0 +1,3 @@
import runner from "@babel/helper-plugin-test-runner";

runner(import.meta.url);
@@ -0,0 +1 @@
{ "type": "module" }

0 comments on commit 52ce528

Please sign in to comment.