sandboxedjs 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.
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Nodepod, DependencyInstaller } from '@scelar/nodepod/headless';
2
+ import { parse as parse$1 } from 'acorn';
2
3
 
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -17947,6 +17948,226 @@ async function readZip(data) {
17947
17948
  function pythonCommands() {
17948
17949
  return [python, pip];
17949
17950
  }
17951
+ var DECLARES_EXPORTS = /(?:^|[\s;{)])(?:var|let|const|function|class)\s+exports\b/;
17952
+ var NAME = "exports";
17953
+ function renameShadowedExports(source) {
17954
+ if (!DECLARES_EXPORTS.test(source)) return null;
17955
+ let ast;
17956
+ try {
17957
+ ast = parse$1(source, {
17958
+ ecmaVersion: "latest",
17959
+ sourceType: "module",
17960
+ allowAwaitOutsideFunction: true,
17961
+ allowHashBang: true
17962
+ });
17963
+ } catch {
17964
+ return null;
17965
+ }
17966
+ const body = ast.body;
17967
+ const isModule = body.some(
17968
+ (node2) => node2.type.startsWith("Import") || node2.type.startsWith("Export")
17969
+ );
17970
+ if (!isModule) return null;
17971
+ const programScope = { bindsExports: hoistedNames(body).has(NAME), parent: null };
17972
+ if (!programScope.bindsExports) return null;
17973
+ const targets = [];
17974
+ let bail = false;
17975
+ visit(ast, programScope);
17976
+ if (bail || targets.length === 0) return null;
17977
+ const replacement = freshName(source);
17978
+ let out = source;
17979
+ for (const target of [...targets].sort((a, b) => b.start - a.start)) {
17980
+ const text = target.shorthand ? `${NAME}: ${replacement}` : replacement;
17981
+ out = out.slice(0, target.start) + text + out.slice(target.end);
17982
+ }
17983
+ return out;
17984
+ function visit(node2, scope) {
17985
+ if (bail) return;
17986
+ let childScope = scope;
17987
+ let skip = NOTHING;
17988
+ switch (node2.type) {
17989
+ case "FunctionDeclaration":
17990
+ case "FunctionExpression":
17991
+ case "ArrowFunctionExpression": {
17992
+ const names = /* @__PURE__ */ new Set();
17993
+ for (const param of node2.params ?? []) collectPattern(param, names);
17994
+ if (isExports(node2.id) && node2.type === "FunctionExpression") names.add(NAME);
17995
+ const fnBody = node2.body;
17996
+ if (fnBody?.type === "BlockStatement") {
17997
+ for (const name of hoistedNames(fnBody.body)) names.add(name);
17998
+ }
17999
+ childScope = { bindsExports: names.has(NAME), parent: scope };
18000
+ break;
18001
+ }
18002
+ case "CatchClause": {
18003
+ const names = /* @__PURE__ */ new Set();
18004
+ if (node2.param) collectPattern(node2.param, names);
18005
+ childScope = { bindsExports: names.has(NAME), parent: scope };
18006
+ break;
18007
+ }
18008
+ case "ClassDeclaration":
18009
+ case "ClassExpression":
18010
+ if (isExports(node2.id) && node2.type === "ClassExpression") {
18011
+ childScope = { bindsExports: true, parent: scope };
18012
+ }
18013
+ break;
18014
+ case "BlockStatement":
18015
+ case "StaticBlock":
18016
+ if (node2 !== ast.body) {
18017
+ childScope = {
18018
+ bindsExports: blockNames(node2.body).has(NAME),
18019
+ parent: scope
18020
+ };
18021
+ }
18022
+ break;
18023
+ case "ForStatement":
18024
+ case "ForInStatement":
18025
+ case "ForOfStatement": {
18026
+ const head2 = node2.init ?? node2.left;
18027
+ if (head2?.type === "VariableDeclaration" && head2.kind !== "var") {
18028
+ const names = /* @__PURE__ */ new Set();
18029
+ for (const declarator of head2.declarations) {
18030
+ collectPattern(declarator.id, names);
18031
+ }
18032
+ childScope = { bindsExports: names.has(NAME), parent: scope };
18033
+ }
18034
+ break;
18035
+ }
18036
+ /* `export { exports }` would have to become `exports as exports`, and
18037
+ * `import { exports as x }` names someone else's binding. Neither is
18038
+ * worth handling; refuse rather than rewrite them wrongly. */
18039
+ case "ExportSpecifier":
18040
+ case "ImportSpecifier":
18041
+ if (isExports(node2.local) || isExports(node2.exported) || isExports(node2.imported)) {
18042
+ bail = true;
18043
+ }
18044
+ return;
18045
+ case "Identifier":
18046
+ if (node2.name === NAME && resolvesToProgram(scope)) {
18047
+ targets.push({ start: node2.start, end: node2.end, shorthand: false });
18048
+ }
18049
+ return;
18050
+ // Property positions are names, not references to the binding.
18051
+ case "MemberExpression":
18052
+ case "MethodDefinition":
18053
+ case "PropertyDefinition":
18054
+ skip = node2.computed ? NOTHING : PROPERTY;
18055
+ break;
18056
+ case "Property":
18057
+ if (node2.computed) break;
18058
+ if (node2.shorthand) {
18059
+ const value = node2.value;
18060
+ if (isExports(value) && resolvesToProgram(scope)) {
18061
+ targets.push({ start: value.start, end: value.end, shorthand: true });
18062
+ }
18063
+ return;
18064
+ }
18065
+ skip = PROPERTY;
18066
+ break;
18067
+ case "LabeledStatement":
18068
+ case "BreakStatement":
18069
+ case "ContinueStatement":
18070
+ skip = LABEL;
18071
+ break;
18072
+ }
18073
+ for (const [key, value] of Object.entries(node2)) {
18074
+ if (key === "type" || key === "start" || key === "end" || skip.includes(key)) continue;
18075
+ if (Array.isArray(value)) {
18076
+ for (const item of value) if (isNode2(item)) visit(item, childScope);
18077
+ } else if (isNode2(value)) {
18078
+ visit(value, childScope);
18079
+ }
18080
+ }
18081
+ }
18082
+ }
18083
+ function resolvesToProgram(scope) {
18084
+ for (let current = scope; current; current = current.parent) {
18085
+ if (current.bindsExports) return current.parent === null;
18086
+ }
18087
+ return false;
18088
+ }
18089
+ function hoistedNames(body) {
18090
+ const names = blockNames(body);
18091
+ collectVars(body, names);
18092
+ return names;
18093
+ }
18094
+ function blockNames(body) {
18095
+ const names = /* @__PURE__ */ new Set();
18096
+ for (const node2 of body ?? []) {
18097
+ if (node2.type === "VariableDeclaration" && node2.kind !== "var") {
18098
+ for (const declarator of node2.declarations) {
18099
+ collectPattern(declarator.id, names);
18100
+ }
18101
+ } else if (node2.type === "ClassDeclaration" && isNode2(node2.id)) {
18102
+ names.add(node2.id.name);
18103
+ } else if (node2.type === "FunctionDeclaration" && isNode2(node2.id)) {
18104
+ names.add(node2.id.name);
18105
+ }
18106
+ }
18107
+ return names;
18108
+ }
18109
+ function collectVars(nodes, names) {
18110
+ if (Array.isArray(nodes)) {
18111
+ for (const item of nodes) collectVars(item, names);
18112
+ return;
18113
+ }
18114
+ if (!isNode2(nodes)) return;
18115
+ const node2 = nodes;
18116
+ if (node2.type === "FunctionDeclaration" || node2.type === "FunctionExpression" || node2.type === "ArrowFunctionExpression") {
18117
+ if (isNode2(node2.id)) names.add(node2.id.name);
18118
+ return;
18119
+ }
18120
+ if (node2.type === "VariableDeclaration" && node2.kind === "var") {
18121
+ for (const declarator of node2.declarations) {
18122
+ collectPattern(declarator.id, names);
18123
+ }
18124
+ }
18125
+ for (const [key, value] of Object.entries(node2)) {
18126
+ if (key === "type" || key === "start" || key === "end") continue;
18127
+ collectVars(value, names);
18128
+ }
18129
+ }
18130
+ function collectPattern(node2, names) {
18131
+ if (!isNode2(node2)) return;
18132
+ switch (node2.type) {
18133
+ case "Identifier":
18134
+ names.add(node2.name);
18135
+ return;
18136
+ case "ObjectPattern":
18137
+ for (const property of node2.properties) {
18138
+ collectPattern(property.value ?? property.argument, names);
18139
+ }
18140
+ return;
18141
+ case "ArrayPattern":
18142
+ for (const element of node2.elements) collectPattern(element, names);
18143
+ return;
18144
+ case "AssignmentPattern":
18145
+ collectPattern(node2.left, names);
18146
+ return;
18147
+ case "RestElement":
18148
+ collectPattern(node2.argument, names);
18149
+ return;
18150
+ default:
18151
+ return;
18152
+ }
18153
+ }
18154
+ function isExports(value) {
18155
+ return isNode2(value) && value.type === "Identifier" && value.name === NAME;
18156
+ }
18157
+ function freshName(source) {
18158
+ let name = "__sandboxedjs_exports";
18159
+ let suffix = 0;
18160
+ while (source.includes(name)) name = `__sandboxedjs_exports${++suffix}`;
18161
+ return name;
18162
+ }
18163
+ function isNode2(value) {
18164
+ return typeof value === "object" && value !== null && typeof value.type === "string";
18165
+ }
18166
+ var NOTHING = [];
18167
+ var PROPERTY = ["property", "key"];
18168
+ var LABEL = ["label"];
18169
+
18170
+ // src/pkg/index.ts
17950
18171
  init_path();
17951
18172
  var NPM_VERSION = "10.9.0";
17952
18173
  function readManifest(ctx, dir3) {
@@ -18008,6 +18229,7 @@ async function installPackages(ctx, specs, opts) {
18008
18229
  }
18009
18230
  }
18010
18231
  normalizeBinDirectories(ctx, opts.cwd);
18232
+ normalizeEsmExports(ctx, opts.cwd);
18011
18233
  return 0;
18012
18234
  } catch (e) {
18013
18235
  ctx.warn(`npm error ${e instanceof Error ? e.message : String(e)}`);
@@ -18231,6 +18453,20 @@ function normalizeBinDirectories(ctx, root) {
18231
18453
  if (basename(path) === ".bin" && path !== join(modules, ".bin")) visit(path);
18232
18454
  }
18233
18455
  }
18456
+ function normalizeEsmExports(ctx, root) {
18457
+ const modules = join(root, "node_modules");
18458
+ if (!ctx.vfs.lexists(modules)) return;
18459
+ for (const path of ctx.vfs.walk(modules, { cred: ctx.cred })) {
18460
+ if (!/\.(?:js|mjs)$/.test(path)) continue;
18461
+ try {
18462
+ if (!ctx.vfs.lstat(path).isFile()) continue;
18463
+ const source = ctx.vfs.readText(path, ctx.cred);
18464
+ const repaired = renameShadowedExports(source);
18465
+ if (repaired !== null) ctx.vfs.writeFile(path, repaired, { privileged: true });
18466
+ } catch {
18467
+ }
18468
+ }
18469
+ }
18234
18470
  function printNpmHelp(ctx) {
18235
18471
  ctx.line(`npm <command>`);
18236
18472
  ctx.line("");