UNPKG

microvium

Version:

A compact, embeddable scripting engine for microcontrollers for executing small scripts written in a subset of JavaScript.

125 lines 6.24 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.nodeStyleImporter = void 0; const utils_1 = require("./utils"); const resolve_1 = __importDefault(require("resolve")); const minimatch_1 = __importDefault(require("minimatch")); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const module_1 = require("module"); /** * Create a node-style module importer for the given VM and options. * * The term "node-style" here refers to the fact that the importer primarily * works around filenames. Module caching is done on the full path */ function nodeStyleImporter(vm, options = {}) { options = { extensions: ['.mvm.js', '.js', '.json'], ...options }; const coreModules = options.coreModules || {}; const rootDir = options.basedir === undefined ? process.cwd() : options.basedir; const fileSystemAccess = options.fileSystemAccess || 'subdir-only'; const moduleCache = new Map(); const rootImporter = makeNestedImporter(rootDir); return rootImporter; // An importer that works relative to a different basedir (e.g. for a nested dependency) function makeNestedImporter(basedir) { return (specifier) => { if (specifier in coreModules) { const coreModule = coreModules[specifier]; // The value can be a specifier for the core module if (typeof coreModule === 'string') { return rootImporter(coreModule); } (0, utils_1.hardAssert)(typeof coreModule === 'object' && coreModule !== null); return coreModule; } // If it's not in the core module list and we can't access the file // system, then we can't import the module if (fileSystemAccess === 'none') { throw new Error(`Module not found: ${(0, utils_1.stringifyIdentifier)(specifier)}`); } // References to files start with `/`, `./` or `../` // https://nodejs.org/api/modules.html#modules_file_modules const isFilePath = /^((\/)|(\.\/)|(\.\.\/))/.test(specifier); const resolved = resolve_1.default.sync(specifier, { ...options, basedir }); const isNodeCoreModule = module_1.builtinModules.includes(resolved); if (isNodeCoreModule) { if (options.allowNodeCoreModules) { return require(resolved); } else { throw new Error(`Module not found: ${(0, utils_1.stringifyIdentifier)(specifier)}`); } } // If it didn't resolve to a file path, and we've already checked // specified core modules and node core modules, then it's not valid if (!isFilePath) { throw new Error(`Module not found: ${(0, utils_1.stringifyIdentifier)(specifier)}`); } const fullModulePath = resolved; const relativePath = path_1.default.relative(rootDir, fullModulePath); if (options.fileSystemAccess === 'subdir-only') { if (path_1.default.posix.normalize(relativePath).startsWith('../')) { throw new Error(`Module not found: ${(0, utils_1.stringifyIdentifier)(specifier)}`); } } if (options.includes) { const isIncluded = options.includes.some(include => (0, minimatch_1.default)(relativePath, include)); if (!isIncluded) { throw new Error(`Module not found: ${(0, utils_1.stringifyIdentifier)(specifier)}`); } } if (options.excludes) { const isIncluded = options.excludes.some(exclude => (0, minimatch_1.default)(relativePath, exclude)); if (!isIncluded) { throw new Error(`Module not found: ${(0, utils_1.stringifyIdentifier)(specifier)}`); } } const fileExtension = path_1.default.extname(fullModulePath).toLowerCase(); if (fileExtension === '.js') { let source; if (moduleCache.has(fullModulePath)) { source = moduleCache.get(fullModulePath); } else { const moduleDir = path_1.default.dirname(fullModulePath); if (!fs_1.default.existsSync(fullModulePath)) { throw new utils_1.MicroviumUsageError(`File not found: "${fullModulePath}"`); } const sourceText = fs_1.default.readFileSync(fullModulePath, 'utf8'); const debugFilename = fullModulePath; const importDependency = makeNestedImporter(moduleDir); (0, utils_1.hardAssert)(typeof sourceText === 'string'); source = { sourceText, debugFilename, importDependency }; moduleCache.set(fullModulePath, source); } const module = vm.evaluateModule(source); return module; } else if (fileExtension === '.json') { const sourceText = fs_1.default.readFileSync(fullModulePath, 'utf8'); const debugFilename = fullModulePath; const value = JSON.parse(sourceText); const importedValue = (0, utils_1.importPodValueRecursive)(vm, value); const source = { sourceText, debugFilename }; moduleCache.set(fullModulePath, source); return importedValue; } else { // Other resources, e.g. JSON return require(fullModulePath); } }; } } exports.nodeStyleImporter = nodeStyleImporter; //# sourceMappingURL=node-style-importer.js.map