Node.js中解析编辑含函数对象的JS文件并保存的方案
Great question! Since JSON doesn't support functions (which is exactly why you're hitting parsing errors), you'll need tools that can handle actual JavaScript syntax—either by safely executing the code in a sandbox or parsing its Abstract Syntax Tree (AST) to modify it without running it. Here are two reliable approaches using Node.js:
1. Use Node.js's vm Module (Simple, for Trusted Files)
If you're working with a file you know is safe, the vm module lets you run the JS code in an isolated context, access the variables directly, modify them, and then regenerate valid JS code to save.
Here's a complete example:
const fs = require('fs'); const vm = require('vm'); // Read your JS file content const jsContent = fs.readFileSync('./your-notifications.js', 'utf8'); // Create an isolated context to hold the executed variables const context = {}; vm.createContext(context); // Run the JS code—variables like `notifications` and `script` will be added to context vm.runInContext(jsContent, context); // Now modify the objects: add a new function-containing entry to notifications context.notifications["NewAlert"] = { title: "New Alert", body: "You've received a new message", icon: "/icons/alert.svg", onClick: function() { console.log("Alert was clicked! Redirecting..."); } }; // Helper to convert objects with functions back to valid JS (JSON.stringify breaks functions) function objToJs(obj) { return JSON.stringify(obj, (key, value) => { if (typeof value === 'function') { return value.toString(); } return value; }) .replace(/"function/g, 'function') // Remove quotes around function declarations .replace(/"}/g, '}'); // Fix closing braces for function properties } // Generate the updated JS content const newJsContent = `let notifications = ${objToJs(context.notifications)}; let script = ${objToJs(context.script)};`; // Save the modified file fs.writeFileSync('./updated-notifications.js', newJsContent, 'utf8');
2. Use AST Parsing Libraries (Safer, for Untrusted Files)
If you're dealing with files from untrusted sources, executing code directly is risky. Instead, use an AST parser like recast (which preserves code formatting) or @babel/parser to modify the code structure without running it.
First, install the dependency:
npm install recast
Then use this code to modify your file:
const fs = require('fs'); const recast = require('recast'); // Read the original JS file const jsContent = fs.readFileSync('./your-notifications.js', 'utf8'); // Parse the code into an Abstract Syntax Tree (AST) const ast = recast.parse(jsContent); // Traverse the AST to find and modify the `notifications` variable recast.visit(ast, { visitVariableDeclaration(path) { const declaration = path.node.declarations[0]; // Check if this is the `notifications` variable we want if (declaration.id.name === 'notifications') { // Create a new object property for our alert const newAlertProp = recast.types.builders.objectProperty( recast.types.builders.literal("NewAlert"), recast.types.builders.objectExpression([ // Add the basic properties recast.types.builders.objectProperty( recast.types.builders.literal("title"), recast.types.builders.literal("New Alert") ), recast.types.builders.objectProperty( recast.types.builders.literal("body"), recast.types.builders.literal("You've received a new message") ), recast.types.builders.objectProperty( recast.types.builders.literal("icon"), recast.types.builders.literal("/icons/alert.svg") ), // Add the onClick function recast.types.builders.objectProperty( recast.types.builders.literal("onClick"), recast.types.builders.functionExpression( null, // No function name [], // No parameters recast.types.builders.blockStatement([ recast.types.builders.expressionStatement( recast.types.builders.callExpression( recast.types.builders.memberExpression( recast.types.builders.identifier("console"), recast.types.builders.identifier("log") ), [recast.types.builders.literal("Alert was clicked! Redirecting...")] ) ) ]) ) ) ]) ); // Add the new property to the notifications object declaration.init.properties.push(newAlertProp); } // Continue traversing other nodes in the AST this.traverse(path); } }); // Generate the modified JS code (preserves original formatting!) const newJsContent = recast.print(ast).code; // Save the updated file fs.writeFileSync('./updated-notifications.js', newJsContent, 'utf8');
Key Notes:
- Security: The
vmmethod is simple but carries risk if the file has malicious code—only use it with trusted files. AST parsing is completely safe because it never executes the original code. - Function Handling:
JSON.stringify()can't handle functions, so we either use a custom serializer (for thevmmethod) or build function nodes directly in the AST (for the parsing method).
内容的提问来源于stack exchange,提问作者Soujanya Barman

