The code imports modules, defines constants, and constructs paths to DLL files, before implementing two functions: buildDLL, which compiles DLLs from code, and makeDLL, which imports and interprets code, then logs extracted namespace information to the console.
npm run import -- "compile a csharp file into a DLL"
const fs = require('fs')
const path = require('path')
const { Module } = require('module')
const BUILD_DIRECTORY = path.join(__dirname, '../.build')
function buildDLL(code, pathToCode, ctx) {
if (!fs.existsSync(BUILD_DIRECTORY)) {
fs.mkdirSync(BUILD_DIRECTORY)
}
const {
importNotebook, interpret
} = require('../Core')
const codeCell = interpret(pathToCode)
// TODO: compare file times for dylib module recompile
const { safeurl } = importNotebook("domain cache tools")
let libName = safeurl(codeCell.questions[0])
let libPath = path.join(BUILD_DIRECTORY, libName + '.cs')
if (!fs.existsSync(libPath)
|| fs.statSync(codeCell.filename).mtime > fs.statSync(libPath).mtime
) {
fs.writeFileSync(libPath, codeCell.source.join(''))
}
// TODO: recompile dylib
let objPath = path.join(BUILD_DIRECTORY, libName + '.dll')
if (!fs.existsSync(objPath)
|| fs.statSync(libPath).mtime > fs.statSync(objPath).mtime
) {
const { spawnSync } = require('child_process')
let args = ['-target:library', '-out:' + objPath, libPath]
spawnSync('mcs', args, { stdio: [0, 1, 2] })
}
}
async function makeDLL(code, pathToCode, ctx) {
if (Module._cache[pathToCode]) {
return Module._cache[pathToCode].exports
}
// TODO: await module loaded
buildDLL(code, pathToCode, ctx)
const {
importNotebook, interpret
} = require('../Core')
const codeCell = interpret(pathToCode)
// TODO: compare file times for dylib module recompile
const { safeurl } = importNotebook("domain cache tools")
let libName = safeurl(codeCell.questions[0])
const selectCode = await importNotebook("select antlr tree")
const rootNode = (await selectCode(['//*'], code.toString(), 'csharp'))[0]
const getClassParams = await importNotebook("list csharp params")
const getClassNames = await importNotebook("list csharp classes")
const getNamespacesBySize = await importNotebook("list csharp namespaces")
const namespace = (await getNamespacesBySize(rootNode))[0]
console.log(namespace)
const dotnet = require('node-api-dotnet')
dotnet.load(path.join(BUILD_DIRECTORY, libName + '.dll'))
const classes = await getClassNames(rootNode, namespace)
console.log(classes)
const params = await getClassParams(rootNode, classes[0])
console.log(params)
// TODO: loop through classes
dotnet[namespace][classes[0]].functions = params.map(p => p[0])
for(let i = 0; i < params.length; i++) {
if(dotnet[namespace][classes[0]][params[i][0]]) {
dotnet[namespace][classes[0]][params[i][0]].params = params
}
}
return dotnet[namespace][classes[0]]
}
module.exports.makeDLL = makeDLL
const fs = require('fs');
const path = require('path');
const { EOL } = require('os');
const { Module } = require('module');
const dotnet = require('node-api-dotnet');
const { spawnSync } = require('child_process');
const BUILD_DIRECTORY = path.join(__dirname, '../.build');
class DLLBuilder {
async buildDLL(code, pathToCode, ctx) {
if (!fs.existsSync(BUILD_DIRECTORY)) {
fs.mkdirSync(BUILD_DIRECTORY);
}
const {
importNotebook,
interpret
} = require('../Core');
const codeCell = await interpret(pathToCode);
const { safeurl } = importNotebook('domain cache tools');
const libName = safeurl(codeCell.questions[0]);
const libPath = path.join(BUILD_DIRECTORY, libName + '.cs');
const lastModified = (await fs.promises.stat(libPath)).mtime;
const file = await fs.promises.stat(codeCell.filename);
if (!fs.existsSync(libPath) || file.mtime > lastModified) {
await fs.promises.writeFile(libPath, codeCell.source.join(EOL));
}
const objPath = path.join(BUILD_DIRECTORY, libName + '.dll');
if (!fs.existsSync(objPath) || lastModified > (await fs.promises.stat(objPath)).mtime) {
const args = ['-target:library', '-out:' + objPath, libPath];
spawnSync('mcs', args, { stdio: [0, 1, 2] });
}
}
}
async function makeDLL(code, pathToCode, ctx) {
if (Module._cache[pathToCode]) {
return Module._cache[pathToCode].exports;
}
const dllBuilder = new DLLBuilder();
await dllBuilder.buildDLL(code, pathToCode, ctx);
const {
importNotebook,
interpret
} = require('../Core');
const codeCell = await interpret(pathToCode);
const { safeurl } = importNotebook('domain cache tools');
const libName = safeurl(codeCell.questions[0]);
const selectCode = await importNotebook('select antlr tree');
const rootNode = (await selectCode(['//*'], code.toString(), 'csharp'))[0];
const getClassParams = await importNotebook('list csharp params');
const getClassNames = await importNotebook('list csharp classes');
const getNamespacesBySize = await importNotebook('list csharp namespaces');
const namespace = (await getNamespacesBySize(rootNode))[0];
console.log(namespace);
dotnet.load(path.join(BUILD_DIRECTORY, libName + '.dll'));
const classes = await getClassNames(rootNode, namespace);
console.log(classes);
const params = await getClassParams(rootNode, classes[0]);
console.log(params);
dotnet[namespace][classes[0]].functions = params.map(p => p[0]);
for (let i = 0; i < params.length; i++) {
if (dotnet[namespace][classes[0]][params[i][0]]) {
dotnet[namespace][classes[0]][params[i][0]].params = params;
}
}
return dotnet[namespace][classes[0]];
}
module.exports.makeDLL = makeDLL;Breakdown of the Code
The code starts by importing the following modules:
fs (File System) for file operationspath for path manipulationModule from the module module (not shown in this snippet)importNotebook and interpret from a local module named ../CoreBUILD_DIRECTORY is defined as the path to a directory named .build in the parent directory of the current module.libName is generated by taking the first question from the codeCell object and passing it to the safeurl function from importNotebook('domain cache tools').libPath is the full path to the DLL file, constructed by joining BUILD_DIRECTORY, libName, and the file extension .cs.objPath is the full path to the DLL file, constructed by joining BUILD_DIRECTORY, libName, and the file extension .dll.The buildDLL function checks if the BUILD_DIRECTORY exists and creates it if not. It then:
importNotebook and interpret functions from ../Core.pathToCode using interpret.spawnSync function from the child_process module to spawn a new process that compiles the DLL using a C# compiler (mcs).The makeDLL function:
pathToCode. If so, it returns the cached exports.buildDLL to compile the DLL.importNotebook and interpret functions from ../Core.pathToCode using interpret.importNotebook to import three notebooks and extract the following information:
libName from safeurl (same as in buildDLL).select antlr tree.list csharp namespaces.Note: This breakdown only includes the code that is presented in the snippet. The actual code may contain additional functionality and dependencies not shown here.