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 ../Core
BUILD_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.