"use strict"; const assert = require("assert"); const types = require("@babel/types"); const template = require("@babel/template").default; const unreachable = require("@joepie91/unreachable")("jsnix"); const NoChange = require("../astformer/actions/no-change"); const ConsumeNode = require("../astformer/actions/consume-node"); const RemoveNode = require("../astformer/actions/remove-node"); const asExpression = require("as-expression"); const unpackExpression = require("./_unpack-expression"); const printAst = require("../print-ast"); // FIXME: Make strict mode! Otherwise objects will inherit from `global` let tmplModule = template(` module.exports = function({ builtins, $$jsNix$extend }) { return %%contents%%; }; `); let tmplLetIn = template(` (() => { %%letBindings%% return %%expression%%; })() `); let tmplObjectDynamic = template(` (() => { let $$nixJS_object = {}; %%entries%% return $$nixJS_object; })() `); let tmplObjectDynamicEntry = template(` if ($$nixJS_object[%%key%%] !== undefined) { throw new Error(\`Duplicate key '\${%%key%%}' in attribute set\`); } $$nixJS_object[%%key%%] = %%wrappedExpression%%; `); let tmplIdentifierReference = template(`( (this?.%%name%% ?? %%name%%)() )`); function generateDynamicObject(bindings, recursive) { let generatedBindings = bindings.map((binding) => { let wrapper = (recursive) ? tmplLazyWrapperRecursive : tmplLazyWrapper; let key = isDynamicBinding(binding) ? binding.attrpath.attr[0] : binding.attrpath.attr[0].name; return tmplObjectDynamicEntry({ key: key, wrappedExpression: wrapper({ expression: binding.expression }) }); }); return tmplObjectDynamic({ entries: generatedBindings.flat() }) } let trivial = { name: "trivial-transforms", visitors: { // Trivial transforms NixParenthesizedExpression: (node) => node.expression, Program: (_node, { setContext, defer }) => { setContext(null, "identifierType", "reference"); return defer((node) => { assert(node.body.length === 1); return tmplModule({ contents: node.body[0] }); }); }, NixIdentifier: (node, { getContext }) => { // FIXME: Mangle reserved keywords like `const` if (getContext("identifierType") === "define") { return types.identifier(node.name); } else { // reference return unpackExpression(tmplIdentifierReference({ name: node.name })); } }, NixBinaryOperation: (_node, { defer }) => { return defer((node) => { // FIXME: Verify that all the 'operator' values match between Nix and JS! return types.binaryExpression(node.operator, node.left, node.right); }); } } }; module.exports = [ require("./desugar-attrsets"), require("./literals"), require("./functions"), require("./attribute-sets"), trivial, ];