Buckets:
| /** | |
| * @license | |
| * Copyright 2010 The Emscripten Authors | |
| * SPDX-License-Identifier: MIT | |
| */ | |
| // General JS utilities - things that might be useful in any JS project. | |
| // Nothing specific to Emscripten appears here. | |
| import * as url from 'node:url'; | |
| import * as path from 'node:path'; | |
| import * as fs from 'node:fs'; | |
| import * as vm from 'node:vm'; | |
| import assert from 'node:assert'; | |
| export function safeQuote(x) { | |
| return x.replace(/"/g, '\\"').replace(/'/g, "\\'"); | |
| } | |
| export function dump(item) { | |
| let funcData; | |
| try { | |
| if (typeof item == 'object' && item != null && item.funcData) { | |
| funcData = item.funcData; | |
| item.funcData = null; | |
| } | |
| return '// ' + JSON.stringify(item, null, ' ').replace(/\n/g, '\n// '); | |
| } catch { | |
| const ret = []; | |
| for (const [i, j] of Object.entries(item)) { | |
| if (typeof j == 'string' || typeof j == 'number') { | |
| ret.push(`${i}: ${j}`); | |
| } else { | |
| ret.push(`${i}: [?]`); | |
| } | |
| } | |
| return ret.join(',\n'); | |
| } finally { | |
| if (funcData) item.funcData = funcData; | |
| } | |
| } | |
| let warnings = false; | |
| export function warningOccured() { | |
| return warnings; | |
| } | |
| let currentFile = []; | |
| export function pushCurrentFile(f) { | |
| currentFile.push(f); | |
| } | |
| export function popCurrentFile() { | |
| currentFile.pop(); | |
| } | |
| function errorPrefix(lineNo) { | |
| if (!currentFile.length) return ''; | |
| const filename = currentFile[currentFile.length - 1]; | |
| if (lineNo) { | |
| return `${filename}:${lineNo}: `; | |
| } else { | |
| return `${filename}: `; | |
| } | |
| } | |
| export function warn(msg, lineNo) { | |
| warnings = true; | |
| printErr(`warning: ${errorPrefix(lineNo)}${msg}`); | |
| } | |
| const seenWarnings = new Set(); | |
| export function warnOnce(msg) { | |
| if (!seenWarnings.has(msg)) { | |
| seenWarnings.add(msg); | |
| warn(msg); | |
| } | |
| } | |
| let abortExecution = false; | |
| export function errorOccured() { | |
| return abortExecution; | |
| } | |
| export function error(msg, lineNo) { | |
| abortExecution = true; | |
| process.exitCode = 1; | |
| printErr(`error: ${errorPrefix(lineNo)}${msg}`); | |
| } | |
| function range(size) { | |
| return Array.from(Array(size).keys()); | |
| } | |
| export function mergeInto(obj, other, options = null) { | |
| if (options) { | |
| // check for unintended symbol redefinition | |
| if (options.noOverride) { | |
| for (const key of Object.keys(other)) { | |
| if (obj.hasOwnProperty(key)) { | |
| error( | |
| `Symbol re-definition in JavaScript library: ${key}. Do not use noOverride if this is intended`, | |
| ); | |
| return; | |
| } | |
| } | |
| } | |
| // check if sig is missing for added functions | |
| if (options.checkSig) { | |
| for (const [key, value] of Object.entries(other)) { | |
| if (typeof value === 'function' && !other.hasOwnProperty(key + '__sig')) { | |
| error(`__sig is missing for function: ${key}. Do not use checkSig if this is intended`); | |
| return; | |
| } | |
| } | |
| } | |
| } | |
| if (!options || !options.allowMissing) { | |
| for (const ident of Object.keys(other)) { | |
| if (isDecorator(ident)) { | |
| const index = ident.lastIndexOf('__'); | |
| const basename = ident.slice(0, index); | |
| if (!(basename in obj) && !(basename in other)) { | |
| error(`Missing library element '${basename}' for library config '${ident}'`); | |
| } | |
| } | |
| } | |
| } | |
| for (const key of Object.keys(other)) { | |
| if (isDecorator(key)) { | |
| if (key.endsWith('__sig')) { | |
| if (obj.hasOwnProperty(key)) { | |
| const oldsig = obj[key]; | |
| const newsig = other[key]; | |
| if (oldsig == newsig) { | |
| warn(`signature redefinition for: ${key}`); | |
| } else { | |
| error(`signature redefinition for: ${key}. (old=${oldsig} vs new=${newsig})`); | |
| } | |
| } | |
| } | |
| const index = key.lastIndexOf('__'); | |
| const decoratorName = key.slice(index); | |
| const type = typeof other[key]; | |
| if (decoratorName == '__async') { | |
| const decorated = key.slice(0, index); | |
| if (isJsOnlySymbol(decorated)) { | |
| error(`__async decorator applied to JS symbol: ${decorated}`); | |
| } | |
| } | |
| // Specific type checking for `__deps` which is expected to be an array | |
| // (not just any old `object`) | |
| if (decoratorName === '__deps') { | |
| const deps = other[key]; | |
| if (!Array.isArray(deps)) { | |
| error( | |
| `JS library directive ${key}=${deps} is of type '${type}', but it should be an array`, | |
| ); | |
| } | |
| for (const dep of deps) { | |
| if (dep && typeof dep !== 'string' && typeof dep !== 'function') { | |
| error( | |
| `__deps entries must be of type 'string' or 'function' not '${typeof dep}': ${key}`, | |
| ); | |
| } | |
| } | |
| } else { | |
| // General type checking for all other decorators | |
| const decoratorTypes = { | |
| __sig: 'string', | |
| __proxy: 'string', | |
| __asm: 'boolean', | |
| __postset: ['string', 'function'], | |
| __docs: 'string', | |
| __nothrow: 'boolean', | |
| __noleakcheck: 'boolean', | |
| __internal: 'boolean', | |
| __user: 'boolean', | |
| __async: ['string', 'boolean'], | |
| __i53abi: 'boolean', | |
| }; | |
| const expected = decoratorTypes[decoratorName]; | |
| if (type !== expected && !expected.includes(type)) { | |
| error(`Decorator (${key}) has wrong type. Expected '${expected}' not '${type}'`); | |
| } | |
| } | |
| } | |
| } | |
| return Object.assign(obj, other); | |
| } | |
| // Symbols that start with '$' are not exported to the wasm module. | |
| // They are intended to be called exclusively by JS code. | |
| export function isJsOnlySymbol(symbol) { | |
| return symbol[0] == '$'; | |
| } | |
| export const decoratorSuffixes = [ | |
| '__sig', | |
| '__proxy', | |
| '__asm', | |
| '__deps', | |
| '__postset', | |
| '__docs', | |
| '__nothrow', | |
| '__noleakcheck', | |
| '__internal', | |
| '__user', | |
| '__async', | |
| '__i53abi', | |
| ]; | |
| export function isDecorator(ident) { | |
| return decoratorSuffixes.some((suffix) => ident.endsWith(suffix)); | |
| } | |
| export function readFile(filename) { | |
| return fs.readFileSync(filename, 'utf8'); | |
| } | |
| // Use import.meta.dirname here once we drop support for node v18. | |
| const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); | |
| export const srcDir = __dirname; | |
| // Returns an absolute path for a file, resolving it relative to this script | |
| // (i.e. relative to the src/ directory). | |
| export function localFile(filename) { | |
| assert(!path.isAbsolute(filename)); | |
| return path.join(srcDir, filename); | |
| } | |
| // Helper function for JS library files that can be used to read files | |
| // relative to the src/ directory. | |
| function read(filename) { | |
| if (!path.isAbsolute(filename)) { | |
| filename = localFile(filename); | |
| } | |
| return readFile(filename); | |
| } | |
| export function printErr(...args) { | |
| console.error(...args); | |
| } | |
| export function debugLog(...args) { | |
| if (VERBOSE) printErr(...args); | |
| } | |
| class Profiler { | |
| ids = []; | |
| lastTime = 0; | |
| constructor() { | |
| this.start('overall') | |
| this.startTime = performance.now(); | |
| } | |
| log(msg) { | |
| const depth = this.ids.length; | |
| const indent = ' '.repeat(depth) | |
| printErr('[prof] ' + indent + msg); | |
| } | |
| start(id) { | |
| this.log(`-> ${id}`) | |
| const now = performance.now(); | |
| this.ids.push([id, now]); | |
| } | |
| stop(id) { | |
| const [poppedId, startTime] = this.ids.pop(); | |
| assert(id === poppedId); | |
| const now = performance.now(); | |
| const duration = now - startTime; | |
| this.log(`<- ${id} [${duration.toFixed(1)} ms]`) | |
| } | |
| terminate() { | |
| while (this.ids.length) { | |
| const lastID = this.ids[this.ids.length - 1][0]; | |
| this.stop(lastID); | |
| } | |
| // const overall = performance.now() - this.startTime | |
| // printErr(`overall total: ${overall.toFixed(1)} ms`); | |
| } | |
| } | |
| class NullProfiler { | |
| start(_id) {} | |
| stop(_id) {} | |
| terminate() {} | |
| } | |
| // Enable JS compiler profiling if EMPROFILE is "2". This mode reports profile | |
| // data to stderr. | |
| const EMPROFILE = process.env.EMPROFILE == '2'; | |
| export const timer = EMPROFILE ? new Profiler() : new NullProfiler(); | |
| if (EMPROFILE) { | |
| process.on('exit', () => timer.terminate()); | |
| } | |
| /** | |
| * Context in which JS library code is evaluated. This is distinct from the | |
| * global scope of the compiler itself which avoids exposing all of the compiler | |
| * internals to user JS library code. | |
| */ | |
| export const compileTimeContext = vm.createContext({ | |
| process, | |
| console, | |
| }); | |
| /** | |
| * A symbols to the macro context. | |
| * This will makes the symbols available to JS library code at build time. | |
| */ | |
| export function addToCompileTimeContext(object) { | |
| Object.assign(compileTimeContext, object); | |
| } | |
| const setLikeSettings = [ | |
| 'EXPORTED_FUNCTIONS', | |
| 'WASM_EXPORTS', | |
| 'SIDE_MODULE_EXPORTS', | |
| 'INCOMING_MODULE_JS_API', | |
| 'ALL_INCOMING_MODULE_JS_API', | |
| 'EXPORTED_RUNTIME_METHODS', | |
| 'WEAK_IMPORTS' | |
| ]; | |
| export function applySettings(obj) { | |
| // Certain settings are read in as lists, but we convert them to Set | |
| // within the compiler, for efficiency. | |
| for (const key of setLikeSettings) { | |
| if (typeof obj[key] !== 'undefined') { | |
| obj[key] = new Set(obj[key]); | |
| } | |
| } | |
| // Make settings available both in the current / global context | |
| // and also in the macro execution context. | |
| Object.assign(globalThis, obj); | |
| addToCompileTimeContext(obj); | |
| } | |
| export function loadSettingsFile(f) { | |
| timer.start('loadSettingsFile') | |
| const settings = {}; | |
| vm.runInNewContext(readFile(f), settings, {filename: f}); | |
| applySettings(settings); | |
| timer.stop('loadSettingsFile') | |
| return settings; | |
| } | |
| export function loadDefaultSettings() { | |
| const rtn = loadSettingsFile(localFile('settings.js')); | |
| Object.assign(rtn, loadSettingsFile(localFile('settings_internal.js'))); | |
| return rtn; | |
| } | |
| export function runInMacroContext(code, options) { | |
| compileTimeContext['__filename'] = options.filename; | |
| compileTimeContext['__dirname'] = path.dirname(options.filename); | |
| return vm.runInContext(code, compileTimeContext, options); | |
| } | |
| addToCompileTimeContext({ | |
| assert, | |
| decoratorSuffixes, | |
| error, | |
| isDecorator, | |
| isJsOnlySymbol, | |
| mergeInto, | |
| read, | |
| warn, | |
| warnOnce, | |
| printErr, | |
| range, | |
| }); | |
Xet Storage Details
- Size:
- 10 kB
- Xet hash:
- cbfb2bdc579c52e22135ee282dcb22e090ca371bdd3d74241067d209c399e889
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.