This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
477 lines
15 KiB
477 lines
15 KiB
'use strict'; |
|
|
|
Object.defineProperty(exports, "__esModule", { |
|
value: true |
|
}); |
|
|
|
var _crypto; |
|
|
|
function _load_crypto() { |
|
return _crypto = _interopRequireDefault(require('crypto')); |
|
} |
|
|
|
var _path; |
|
|
|
function _load_path() { |
|
return _path = _interopRequireDefault(require('path')); |
|
} |
|
|
|
var _vm; |
|
|
|
function _load_vm() { |
|
return _vm = _interopRequireDefault(require('vm')); |
|
} |
|
|
|
var _jestUtil; |
|
|
|
function _load_jestUtil() { |
|
return _jestUtil = require('jest-util'); |
|
} |
|
|
|
var _gracefulFs; |
|
|
|
function _load_gracefulFs() { |
|
return _gracefulFs = _interopRequireDefault(require('graceful-fs')); |
|
} |
|
|
|
var _babelCore; |
|
|
|
function _load_babelCore() { |
|
return _babelCore = require('babel-core'); |
|
} |
|
|
|
var _babelPluginIstanbul; |
|
|
|
function _load_babelPluginIstanbul() { |
|
return _babelPluginIstanbul = _interopRequireDefault(require('babel-plugin-istanbul')); |
|
} |
|
|
|
var _convertSourceMap; |
|
|
|
function _load_convertSourceMap() { |
|
return _convertSourceMap = _interopRequireDefault(require('convert-source-map')); |
|
} |
|
|
|
var _jestHasteMap; |
|
|
|
function _load_jestHasteMap() { |
|
return _jestHasteMap = _interopRequireDefault(require('jest-haste-map')); |
|
} |
|
|
|
var _jsonStableStringify; |
|
|
|
function _load_jsonStableStringify() { |
|
return _jsonStableStringify = _interopRequireDefault(require('json-stable-stringify')); |
|
} |
|
|
|
var _slash; |
|
|
|
function _load_slash() { |
|
return _slash = _interopRequireDefault(require('slash')); |
|
} |
|
|
|
var _package; |
|
|
|
function _load_package() { |
|
return _package = require('../package.json'); |
|
} |
|
|
|
var _should_instrument; |
|
|
|
function _load_should_instrument() { |
|
return _should_instrument = _interopRequireDefault(require('./should_instrument')); |
|
} |
|
|
|
var _writeFileAtomic; |
|
|
|
function _load_writeFileAtomic() { |
|
return _writeFileAtomic = _interopRequireDefault(require('write-file-atomic')); |
|
} |
|
|
|
var _realpathNative; |
|
|
|
function _load_realpathNative() { |
|
return _realpathNative = require('realpath-native'); |
|
} |
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } |
|
|
|
const cache = new Map(); /** |
|
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved. |
|
* |
|
* This source code is licensed under the MIT license found in the |
|
* LICENSE file in the root directory of this source tree. |
|
* |
|
* |
|
*/ |
|
|
|
const configToJsonMap = new Map(); |
|
// Cache regular expressions to test whether the file needs to be preprocessed |
|
const ignoreCache = new WeakMap(); |
|
|
|
// To reset the cache for specific changesets (rather than package version). |
|
const CACHE_VERSION = '1'; |
|
|
|
class ScriptTransformer { |
|
|
|
constructor(config) { |
|
this._config = config; |
|
this._transformCache = new Map(); |
|
} |
|
|
|
_getCacheKey(fileData, filename, instrument) { |
|
if (!configToJsonMap.has(this._config)) { |
|
// We only need this set of config options that can likely influence |
|
// cached output instead of all config options. |
|
configToJsonMap.set(this._config, (0, (_jsonStableStringify || _load_jsonStableStringify()).default)(this._config)); |
|
} |
|
const configString = configToJsonMap.get(this._config) || ''; |
|
const transformer = this._getTransformer(filename); |
|
|
|
if (transformer && typeof transformer.getCacheKey === 'function') { |
|
return (_crypto || _load_crypto()).default.createHash('md5').update(transformer.getCacheKey(fileData, filename, configString, { |
|
instrument, |
|
rootDir: this._config.rootDir |
|
})).update(CACHE_VERSION).digest('hex'); |
|
} else { |
|
return (_crypto || _load_crypto()).default.createHash('md5').update(fileData).update(configString).update(instrument ? 'instrument' : '').update(CACHE_VERSION).digest('hex'); |
|
} |
|
} |
|
|
|
_getFileCachePath(filename, content, instrument) { |
|
const baseCacheDir = (_jestHasteMap || _load_jestHasteMap()).default.getCacheFilePath(this._config.cacheDirectory, 'jest-transform-cache-' + this._config.name, (_package || _load_package()).version); |
|
const cacheKey = this._getCacheKey(content, filename, instrument); |
|
// Create sub folders based on the cacheKey to avoid creating one |
|
// directory with many files. |
|
const cacheDir = (_path || _load_path()).default.join(baseCacheDir, cacheKey[0] + cacheKey[1]); |
|
const cachePath = (0, (_slash || _load_slash()).default)((_path || _load_path()).default.join(cacheDir, (_path || _load_path()).default.basename(filename, (_path || _load_path()).default.extname(filename)) + '_' + cacheKey)); |
|
(0, (_jestUtil || _load_jestUtil()).createDirectory)(cacheDir); |
|
|
|
return cachePath; |
|
} |
|
|
|
_getTransformPath(filename) { |
|
for (let i = 0; i < this._config.transform.length; i++) { |
|
if (new RegExp(this._config.transform[i][0]).test(filename)) { |
|
return this._config.transform[i][1]; |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
_getTransformer(filename) { |
|
let transform; |
|
if (!this._config.transform || !this._config.transform.length) { |
|
return null; |
|
} |
|
|
|
const transformPath = this._getTransformPath(filename); |
|
if (transformPath) { |
|
const transformer = this._transformCache.get(transformPath); |
|
if (transformer != null) { |
|
return transformer; |
|
} |
|
|
|
// $FlowFixMe |
|
transform = require(transformPath); |
|
if (typeof transform.process !== 'function') { |
|
throw new TypeError('Jest: a transform must export a `process` function.'); |
|
} |
|
if (typeof transform.createTransformer === 'function') { |
|
transform = transform.createTransformer(); |
|
} |
|
this._transformCache.set(transformPath, transform); |
|
} |
|
return transform; |
|
} |
|
|
|
_instrumentFile(filename, content) { |
|
return (0, (_babelCore || _load_babelCore()).transform)(content, { |
|
auxiliaryCommentBefore: ' istanbul ignore next ', |
|
babelrc: false, |
|
filename, |
|
plugins: [[(_babelPluginIstanbul || _load_babelPluginIstanbul()).default, { |
|
// files outside `cwd` will not be instrumented |
|
cwd: this._config.rootDir, |
|
exclude: [], |
|
useInlineSourceMaps: false |
|
}]], |
|
retainLines: true |
|
}).code; |
|
} |
|
|
|
_getRealPath(filepath) { |
|
try { |
|
return (0, (_realpathNative || _load_realpathNative()).sync)(filepath) || filepath; |
|
} catch (err) { |
|
return filepath; |
|
} |
|
} |
|
|
|
transformSource(filepath, content, instrument) { |
|
const filename = this._getRealPath(filepath); |
|
const transform = this._getTransformer(filename); |
|
const cacheFilePath = this._getFileCachePath(filename, content, instrument); |
|
let sourceMapPath = cacheFilePath + '.map'; |
|
// Ignore cache if `config.cache` is set (--no-cache) |
|
let code = this._config.cache ? readCodeCacheFile(cacheFilePath) : null; |
|
|
|
const shouldCallTransform = transform && shouldTransform(filename, this._config); |
|
|
|
// That means that the transform has a custom instrumentation |
|
// logic and will handle it based on `config.collectCoverage` option |
|
const transformWillInstrument = shouldCallTransform && transform && transform.canInstrument; |
|
|
|
// If we handle the coverage instrumentation, we should try to map code |
|
// coverage against original source with any provided source map |
|
const mapCoverage = instrument && !transformWillInstrument; |
|
|
|
if (code) { |
|
// This is broken: we return the code, and a path for the source map |
|
// directly from the cache. But, nothing ensures the source map actually |
|
// matches that source code. They could have gotten out-of-sync in case |
|
// two separate processes write concurrently to the same cache files. |
|
return { |
|
code, |
|
mapCoverage, |
|
sourceMapPath |
|
}; |
|
} |
|
|
|
let transformed = { |
|
code: content, |
|
map: null |
|
}; |
|
|
|
if (transform && shouldCallTransform) { |
|
const processed = transform.process(content, filename, this._config, { |
|
instrument, |
|
returnSourceString: false |
|
}); |
|
|
|
if (typeof processed === 'string') { |
|
transformed.code = processed; |
|
} else if (processed != null && typeof processed.code === 'string') { |
|
transformed = processed; |
|
} else { |
|
throw new TypeError("Jest: a transform's `process` function must return a string, " + 'or an object with `code` key containing this string.'); |
|
} |
|
} |
|
|
|
if (!transformed.map) { |
|
//Could be a potential freeze here. |
|
//See: https://github.com/facebook/jest/pull/5177#discussion_r158883570 |
|
const inlineSourceMap = (_convertSourceMap || _load_convertSourceMap()).default.fromSource(transformed.code); |
|
if (inlineSourceMap) { |
|
transformed.map = inlineSourceMap.toJSON(); |
|
} |
|
} |
|
|
|
if (!transformWillInstrument && instrument) { |
|
code = this._instrumentFile(filename, transformed.code); |
|
} else { |
|
code = transformed.code; |
|
} |
|
|
|
if (transformed.map) { |
|
const sourceMapContent = typeof transformed.map === 'string' ? transformed.map : JSON.stringify(transformed.map); |
|
writeCacheFile(sourceMapPath, sourceMapContent); |
|
} else { |
|
sourceMapPath = null; |
|
} |
|
|
|
writeCodeCacheFile(cacheFilePath, code); |
|
|
|
return { |
|
code, |
|
mapCoverage, |
|
sourceMapPath |
|
}; |
|
} |
|
|
|
_transformAndBuildScript(filename, options, instrument, fileSource) { |
|
const isInternalModule = !!(options && options.isInternalModule); |
|
const isCoreModule = !!(options && options.isCoreModule); |
|
const content = stripShebang(fileSource || (_gracefulFs || _load_gracefulFs()).default.readFileSync(filename, 'utf8')); |
|
|
|
let wrappedCode; |
|
let sourceMapPath = null; |
|
let mapCoverage = false; |
|
|
|
const willTransform = !isInternalModule && !isCoreModule && (shouldTransform(filename, this._config) || instrument); |
|
|
|
try { |
|
if (willTransform) { |
|
const transformedSource = this.transformSource(filename, content, instrument); |
|
|
|
wrappedCode = wrap(transformedSource.code); |
|
sourceMapPath = transformedSource.sourceMapPath; |
|
mapCoverage = transformedSource.mapCoverage; |
|
} else { |
|
wrappedCode = wrap(content); |
|
} |
|
|
|
return { |
|
mapCoverage, |
|
script: new (_vm || _load_vm()).default.Script(wrappedCode, { |
|
displayErrors: true, |
|
filename: isCoreModule ? 'jest-nodejs-core-' + filename : filename |
|
}), |
|
sourceMapPath |
|
}; |
|
} catch (e) { |
|
if (e.codeFrame) { |
|
e.stack = e.codeFrame; |
|
} |
|
|
|
throw e; |
|
} |
|
} |
|
|
|
transform(filename, options, fileSource) { |
|
let scriptCacheKey = null; |
|
let instrument = false; |
|
let result = ''; |
|
|
|
if (!options.isCoreModule) { |
|
instrument = (0, (_should_instrument || _load_should_instrument()).default)(filename, options, this._config); |
|
scriptCacheKey = getScriptCacheKey(filename, this._config, instrument); |
|
result = cache.get(scriptCacheKey); |
|
} |
|
|
|
if (result) { |
|
return result; |
|
} |
|
|
|
result = this._transformAndBuildScript(filename, options, instrument, fileSource); |
|
|
|
if (scriptCacheKey) { |
|
cache.set(scriptCacheKey, result); |
|
} |
|
|
|
return result; |
|
} |
|
} |
|
|
|
exports.default = ScriptTransformer; |
|
const removeFile = path => { |
|
try { |
|
(_gracefulFs || _load_gracefulFs()).default.unlinkSync(path); |
|
} catch (e) {} |
|
}; |
|
|
|
const stripShebang = content => { |
|
// If the file data starts with a shebang remove it. Leaves the empty line |
|
// to keep stack trace line numbers correct. |
|
if (content.startsWith('#!')) { |
|
return content.replace(/^#!.*/, ''); |
|
} else { |
|
return content; |
|
} |
|
}; |
|
|
|
/** |
|
* This is like `writeCacheFile` but with an additional sanity checksum. We |
|
* cannot use the same technique for source maps because we expose source map |
|
* cache file paths directly to callsites, with the expectation they can read |
|
* it right away. This is not a great system, because source map cache file |
|
* could get corrupted, out-of-sync, etc. |
|
*/ |
|
function writeCodeCacheFile(cachePath, code) { |
|
const checksum = (_crypto || _load_crypto()).default.createHash('md5').update(code).digest('hex'); |
|
writeCacheFile(cachePath, checksum + '\n' + code); |
|
} |
|
|
|
/** |
|
* Read counterpart of `writeCodeCacheFile`. We verify that the content of the |
|
* file matches the checksum, in case some kind of corruption happened. This |
|
* could happen if an older version of `jest-runtime` writes non-atomically to |
|
* the same cache, for example. |
|
*/ |
|
function readCodeCacheFile(cachePath) { |
|
const content = readCacheFile(cachePath); |
|
if (content == null) { |
|
return null; |
|
} |
|
const code = content.substr(33); |
|
const checksum = (_crypto || _load_crypto()).default.createHash('md5').update(code).digest('hex'); |
|
if (checksum === content.substr(0, 32)) { |
|
return code; |
|
} |
|
return null; |
|
} |
|
|
|
/** |
|
* Writing to the cache atomically relies on 'rename' being atomic on most |
|
* file systems. Doing atomic write reduces the risk of corruption by avoiding |
|
* two processes to write to the same file at the same time. It also reduces |
|
* the risk of reading a file that's being overwritten at the same time. |
|
*/ |
|
const writeCacheFile = (cachePath, fileData) => { |
|
try { |
|
(_writeFileAtomic || _load_writeFileAtomic()).default.sync(cachePath, fileData, { encoding: 'utf8' }); |
|
} catch (e) { |
|
if (cacheWriteErrorSafeToIgnore(e, cachePath)) { |
|
return; |
|
} |
|
|
|
e.message = 'jest: failed to cache transform results in: ' + cachePath + '\nFailure message: ' + e.message; |
|
removeFile(cachePath); |
|
throw e; |
|
} |
|
}; |
|
|
|
/** |
|
* On Windows, renames are not atomic, leading to EPERM exceptions when two |
|
* processes attempt to rename to the same target file at the same time. |
|
* If the target file exists we can be reasonably sure another process has |
|
* legitimately won a cache write race and ignore the error. |
|
*/ |
|
const cacheWriteErrorSafeToIgnore = (e, cachePath) => { |
|
return process.platform === 'win32' && e.code === 'EPERM' && (_gracefulFs || _load_gracefulFs()).default.existsSync(cachePath); |
|
}; |
|
|
|
const readCacheFile = cachePath => { |
|
if (!(_gracefulFs || _load_gracefulFs()).default.existsSync(cachePath)) { |
|
return null; |
|
} |
|
|
|
let fileData; |
|
try { |
|
fileData = (_gracefulFs || _load_gracefulFs()).default.readFileSync(cachePath, 'utf8'); |
|
} catch (e) { |
|
e.message = 'jest: failed to read cache file: ' + cachePath + '\nFailure message: ' + e.message; |
|
removeFile(cachePath); |
|
throw e; |
|
} |
|
|
|
if (fileData == null) { |
|
// We must have somehow created the file but failed to write to it, |
|
// let's delete it and retry. |
|
removeFile(cachePath); |
|
} |
|
return fileData; |
|
}; |
|
|
|
const getScriptCacheKey = (filename, config, instrument) => { |
|
const mtime = (_gracefulFs || _load_gracefulFs()).default.statSync(filename).mtime; |
|
return filename + '_' + mtime.getTime() + (instrument ? '_instrumented' : ''); |
|
}; |
|
|
|
const shouldTransform = (filename, config) => { |
|
if (!ignoreCache.has(config)) { |
|
if (!config.transformIgnorePatterns || config.transformIgnorePatterns.length === 0) { |
|
ignoreCache.set(config, null); |
|
} else { |
|
ignoreCache.set(config, new RegExp(config.transformIgnorePatterns.join('|'))); |
|
} |
|
} |
|
|
|
const ignoreRegexp = ignoreCache.get(config); |
|
const isIgnored = ignoreRegexp ? ignoreRegexp.test(filename) : false; |
|
return !!config.transform && !!config.transform.length && !isIgnored; |
|
}; |
|
|
|
const wrap = content => '({"' + ScriptTransformer.EVAL_RESULT_VARIABLE + '":function(module,exports,require,__dirname,__filename,global,jest){' + content + '\n}});'; |
|
|
|
ScriptTransformer.EVAL_RESULT_VARIABLE = 'Object.<anonymous>'; |