UNPKG

elm-review

Version:
578 lines (553 loc) 14.5 kB
/** * @import {Options} from './types/options'; * @import {Optimization} from './types/optimize-js'; */ const Benchmark = require('./benchmark'); const FS = require('./fs-wrapper'); /** * @param {Options} options * @param {string | null} elmModulePath * @param {boolean} isReviewApp * @returns {Promise<string | null>} */ async function optimize(options, elmModulePath, isReviewApp) { if (options.debug || !elmModulePath) { return elmModulePath; } const timerId = isReviewApp ? 'optimizing review application' : 'optimizing parser application'; Benchmark.start(options, timerId); const originalSource = await FS.readFile(elmModulePath); const packageName = options.localElmReviewSrc ? '$author$project' : '$jfmengels$elm_review'; const replacements = isReviewApp ? [ ...coreElmPerformanceReplacements.map((replacement) => [replacement]), fasterCreateRuleModuleVisitor(packageName), mutatingMapReplacement(packageName), ...cacheReplacements(packageName).map((replacement) => [replacement]) ] : coreElmPerformanceReplacements.map((replacement) => [replacement]); const newSource = applyReplacements(originalSource, replacements); await FS.writeFile(elmModulePath, newSource); Benchmark.end(options, timerId); return elmModulePath; } /** * @param {string} originalSource * @param {Optimization[][]} replacementGroups * @returns {string} */ function applyReplacements(originalSource, replacementGroups) { return replacementGroups.reduce(applyReplacementForGroups, originalSource); } /** Apply all replacements of a group. If any of the replacements can't be applied, then apply none of them. * @param {string} originalSource * @param {Optimization[]} replacementGroup * @returns {string} */ function applyReplacementForGroups(originalSource, replacementGroup) { let source = originalSource; for (const {target, replacement} of replacementGroup) { if (!source.includes(target)) { return originalSource; } source = source.replace(target, replacement); } return source; } const coreElmPerformanceReplacements = [ { target: `var $elm$core$List$all = F2( \tfunction (isOkay, list) { \t\treturn !A2( \t\t\t$elm$core$List$any, \t\t\tA2($elm$core$Basics$composeL, $elm$core$Basics$not, isOkay), \t\t\tlist); \t});`, replacement: `var $elm$core$List$all = F2(function (isOkay, list) { all: while (true) { if (!list.b) { return true; } else { var x = list.a; if (!isOkay(x)) { return false; } list = list.b; continue all; } } });` }, { target: `var $elm$core$List$append = F2( \tfunction (xs, ys) { \t\tif (!ys.b) { \t\t\treturn xs; \t\t} else { \t\t\treturn A3($elm$core$List$foldr, $elm$core$List$cons, ys, xs); \t\t} \t});`, replacement: `var $elm$core$List$append = F2(function (xs, ys) { var tmp = _List_Cons(undefined, _List_Nil); var end = tmp; for (; xs.b; xs = xs.b) { var next = _List_Cons(xs.a, _List_Nil); end.b = next; end = next; } end.b = ys; return tmp.b; });` }, { target: `var $elm$core$List$concat = function (lists) { \treturn A3($elm$core$List$foldr, $elm$core$List$append, _List_Nil, lists); };`, replacement: `var $elm$core$List$concat = function (lists) { if (!lists.b) { return _List_Nil; } var tmp = _List_Cons(undefined, _List_Nil); var end = tmp; for (; lists.b.b; lists = lists.b) { var xs = lists.a; for (; xs.b; xs = xs.b) { var next = _List_Cons(xs.a, _List_Nil); end.b = next; end = next; } } end.b = lists.a; return tmp.b; };` }, { target: `var $elm$core$List$concatMap = F2( \tfunction (f, list) { \t\treturn $elm$core$List$concat( \t\t\tA2($elm$core$List$map, f, list)); \t});`, replacement: `var $elm$core$List$concatMap = F2(function (f, lists) { if (!lists.b) { return _List_Nil; } var tmp = _List_Cons(undefined, _List_Nil); var end = tmp; for (; lists.b.b; lists = lists.b) { var xs = f(lists.a); for (; xs.b; xs = xs.b) { var next = _List_Cons(xs.a, _List_Nil); end.b = next; end = next; } } end.b = f(lists.a); return tmp.b; });` }, { target: `var $elm$core$List$filter = F2( \tfunction (isGood, list) { \t\treturn A3( \t\t\t$elm$core$List$foldr, \t\t\tF2( \t\t\t\tfunction (x, xs) { \t\t\t\t\treturn isGood(x) ? A2($elm$core$List$cons, x, xs) : xs; \t\t\t\t}), \t\t\t_List_Nil, \t\t\tlist); \t});`, replacement: `var $elm$core$List$filter = F2(function (f, xs) { var tmp = _List_Cons(undefined, _List_Nil); var end = tmp; for (; xs.b; xs = xs.b) { if (f(xs.a)) { var next = _List_Cons(xs.a, _List_Nil); end.b = next; end = next; } } return tmp.b; });` }, { target: `var $elm$core$List$indexedMap = F2( \tfunction (f, xs) { \t\treturn A3( \t\t\t$elm$core$List$map2, \t\t\tf, \t\t\tA2( \t\t\t\t$elm$core$List$range, \t\t\t\t0, \t\t\t\t$elm$core$List$length(xs) - 1), \t\t\txs); \t});`, replacement: `var $elm$core$List$indexedMap = F2(function (f, xs) { var tmp = _List_Cons(undefined, _List_Nil); var end = tmp; for (var i = 0; xs.b; i++, xs = xs.b) { var next = _List_Cons(A2(f, i, xs.a), _List_Nil); end.b = next; end = next; } return tmp.b; });` }, { target: `var $elm$core$List$intersperse = F2( \tfunction (sep, xs) { \t\tif (!xs.b) { \t\t\treturn _List_Nil; \t\t} else { \t\t\tvar hd = xs.a; \t\t\tvar tl = xs.b; \t\t\tvar step = F2( \t\t\t\tfunction (x, rest) { \t\t\t\t\treturn A2( \t\t\t\t\t\t$elm$core$List$cons, \t\t\t\t\t\tsep, \t\t\t\t\t\tA2($elm$core$List$cons, x, rest)); \t\t\t\t}); \t\t\tvar spersed = A3($elm$core$List$foldr, step, _List_Nil, tl); \t\t\treturn A2($elm$core$List$cons, hd, spersed); \t\t} \t});`, replacement: `var $elm$core$List$intersperse = F2(function (sep, xs) { if (!xs.b) { return xs; } var tmp = _List_Cons(undefined, _List_Nil); var end = tmp; end.b = _List_Cons(xs.a, _List_Nil); end = end.b; xs = xs.b; for (; xs.b; xs = xs.b) { var valNode = _List_Cons(xs.a, _List_Nil); var sepNode = _List_Cons(sep, valNode); end.b = sepNode; end = valNode; } return tmp.b; });` }, { target: `var $elm$core$List$map = F2( \tfunction (f, xs) { \t\treturn A3( \t\t\t$elm$core$List$foldr, \t\t\tF2( \t\t\t\tfunction (x, acc) { \t\t\t\t\treturn A2( \t\t\t\t\t\t$elm$core$List$cons, \t\t\t\t\t\tf(x), \t\t\t\t\t\tacc); \t\t\t\t}), \t\t\t_List_Nil, \t\t\txs); \t});`, replacement: `var $elm$core$List$map = F2(function (f, xs) { var tmp = _List_Cons(undefined, _List_Nil); var end = tmp; for (; xs.b; xs = xs.b) { var next = _List_Cons(f(xs.a), _List_Nil); end.b = next; end = next; } return tmp.b; });` }, { target: `var $elm$core$List$partition = F2( \tfunction (pred, list) { \t\tvar step = F2( \t\t\tfunction (x, _v0) { \t\t\t\tvar trues = _v0.a; \t\t\t\tvar falses = _v0.b; \t\t\t\treturn pred(x) ? _Utils_Tuple2( \t\t\t\t\tA2($elm$core$List$cons, x, trues), \t\t\t\t\tfalses) : _Utils_Tuple2( \t\t\t\t\ttrues, \t\t\t\t\tA2($elm$core$List$cons, x, falses)); \t\t\t}); \t\treturn A3( \t\t\t$elm$core$List$foldr, \t\t\tstep, \t\t\t_Utils_Tuple2(_List_Nil, _List_Nil), \t\t\tlist); \t});`, replacement: `var $elm$core$List$partition = F2(function (f, xs) { var truesHead = _List_Cons(undefined, _List_Nil); var falsesHead = _List_Cons(undefined, _List_Nil); var truesEnd = truesHead; var falsesEnd = falsesHead; for (; xs.b; xs = xs.b) { var next = _List_Cons(xs.a, _List_Nil); if (f(xs.a)) { truesEnd.b = next; truesEnd = next; } else { falsesEnd.b = next; falsesEnd = next; } } return _Utils_Tuple2(truesHead.b, falsesHead.b); });` }, { target: `var $elm$core$List$take = F2( \tfunction (n, list) { \t\treturn A3($elm$core$List$takeFast, 0, n, list); \t});`, replacement: `var $elm$core$List$take = F2(function(n, xs) { var tmp = _List_Cons(undefined, _List_Nil); var end = tmp; for (var i = 0; i < n && xs.b; xs = xs.b, i++) { var next = _List_Cons(xs.a, _List_Nil); end.b = next; end = next; } return tmp.b; });` }, { target: `var $elm$core$List$unzip = function (pairs) { \tvar step = F2( \t\tfunction (_v0, _v1) { \t\t\tvar x = _v0.a; \t\t\tvar y = _v0.b; \t\t\tvar xs = _v1.a; \t\t\tvar ys = _v1.b; \t\t\treturn _Utils_Tuple2( \t\t\t\tA2($elm$core$List$cons, x, xs), \t\t\t\tA2($elm$core$List$cons, y, ys)); \t\t}); \treturn A3( \t\t$elm$core$List$foldr, \t\tstep, \t\t_Utils_Tuple2(_List_Nil, _List_Nil), \t\tpairs); };`, replacement: `var $elm$core$List$unzip = function (pairs) { var aHead = _List_Cons(undefined, _List_Nil); var bHead = _List_Cons(undefined, _List_Nil); var aEnd = aHead; var bEnd = bHead; for (; pairs.b; pairs = pairs.b) { var tuple = pairs.a; var aNext = _List_Cons(tuple.a, _List_Nil); aEnd.b = aNext; aEnd = aNext; var bNext = _List_Cons(tuple.b, _List_Nil); bEnd.b = bNext; bEnd = bNext; } return _Utils_Tuple2(aHead.b, bHead.b); };` }, { target: `var $elm$core$List$filterMap = F2( \tfunction (f, xs) { \t\treturn A3( \t\t\t$elm$core$List$foldr, \t\t\t$elm$core$List$maybeCons(f), \t\t\t_List_Nil, \t\t\txs); \t});`, replacement: `var $elm$core$List$filterMap = F2(function (f, xs) { var tmp = _List_Cons(undefined, _List_Nil); var end = tmp; for (; xs.b; xs = xs.b) { var m = f(xs.a); if (!m.$) { var next = _List_Cons(m.a, _List_Nil); end.b = next; end = next; } } return tmp.b; });` }, { target: `var $elm$core$Set$map = F2( \tfunction (func, set) { \t\treturn $elm$core$Set$fromList( \t\t\tA3( \t\t\t\t$elm$core$Set$foldl, \t\t\t\tF2( \t\t\t\t\tfunction (x, xs) { \t\t\t\t\t\treturn A2( \t\t\t\t\t\t\t$elm$core$List$cons, \t\t\t\t\t\t\tfunc(x), \t\t\t\t\t\t\txs); \t\t\t\t\t}), \t\t\t\t_List_Nil, \t\t\t\tset)); \t});`, replacement: `var $elm$core$Set$map = F2( function (func, set) { return A3( $elm$core$Set$foldl, F2( function (x, acc) { return A2( $elm$core$Set$insert, func(x), acc); }), $elm$core$Set$empty, set); });` }, { target: `var $elm$core$Basics$composeL = F3( function (g, f, x) { return g( f(x)); });`, replacement: `var $elm$core$Basics$composeL = F2(function $elm$core$Basics$composeL$fn(g, f) { return function(x) { return g(f(x)); }; });` }, { target: `var $elm$core$Basics$composeR = F3( function (f, g, x) { return g( f(x)); });`, replacement: `var $elm$core$Basics$composeR = F2(function $elm$core$Basics$composeR$fn(f, g) { return function(x) { return g(f(x)); }; });` } ]; /** * @param {string} packageName * @returns {Optimization[]} */ function fasterCreateRuleModuleVisitor(packageName) { return [ { target: `var ${packageName}$Review$Rule$createRuleModuleVisitor = F4( \tfunction (schema, params, toRuleProjectVisitor, initialContext) { \t\tvar raise = function (errorsAndContext) { \t\t\treturn {`, replacement: `var ${packageName}$Review$Rule$createRuleModuleVisitor = F4( function (schema, params, toRuleProjectVisitor, initialContext) { var raise = function (errorsAndContext) { function raise(_v0) { errorsAndContext.a = _v0.a; errorsAndContext.b = _v0.b; } return {` } ]; } /** * @param {string} packageName * @returns {Optimization[]} */ function mutatingMapReplacement(packageName) { return [ { target: `var ${packageName}$Review$Rule$fromJsArrayToList = function (_v0) { \tvar list = _v0; \treturn list; };`, replacement: `var ${packageName}$Review$Rule$fromJsArrayToList = _List_fromArray;` }, { target: `var ${packageName}$Review$Rule$fromListToJsArray = $elm$core$Basics$identity;`, replacement: `var ${packageName}$Review$Rule$fromListToJsArray = _List_toArray;` }, { target: `var ${packageName}$Review$Rule$mutatingMap = F2( \tfunction (mapper, _v0) { \t\tvar list = _v0; \t\treturn A2($elm$core$List$map, mapper, list); \t});`, replacement: `var ${packageName}$Review$Rule$mutatingMap = F2( function (mapper, arr) { var len = arr.length; for (var i = 0; i < len; i++) { mapper(arr[i]); } return arr; });` }, { target: `var ${packageName}$Review$Cache$ContextHash$sort = $elm$core$Basics$identity;`, replacement: `var ${packageName}$Review$Cache$ContextHash$sort = function(l) { return $elm$core$List$sort(l); }` } ]; } /** * @param {string} packageName * @returns {Optimization[]} */ function cacheReplacements(packageName) { return [ { target: `var ${packageName}$Review$Rule$initialCacheMarker = F3( \tfunction (_v0, _v1, cache) { \t\treturn cache; \t});`, replacement: `var ${packageName}$Review$Rule$initialCacheMarker = F3( function (ruleName, ruleId, defaultCache) { return globalThis.loadResultFromCache(ruleName, ruleId) || defaultCache; });` }, { target: `var ${packageName}$Review$Rule$finalCacheMarker = F3( \tfunction (_v0, _v1, cache) { \t\treturn cache; \t});`, replacement: `var ${packageName}$Review$Rule$finalCacheMarker = F3( function (ruleName, ruleId, cacheEntry) { globalThis.saveResultToCache(ruleName, ruleId, cacheEntry); return cacheEntry; });` }, { target: `var ${packageName}$Review$Cache$ContextHash$createContextHashMarker = function (context) { \treturn context; };`, replacement: `var ${packageName}$Review$Cache$ContextHash$createContextHashMarker = function (context) { return jsonToHash(contextToJson(context)); }; const stringifyMap = new WeakMap(); function contextToJson(context) { const isObject = typeof context === 'object'; if (!isObject) { return JSON.stringify(context); } if (stringifyMap.has(context)) { return stringifyMap.get(context); } else { const json = JSON.stringify(context, globalThis.elmJsonReplacer); stringifyMap.set(context, json); return json; } } const contextHashMap = new Map(); function jsonToHash(json) { if (contextHashMap.has(json)) { return contextHashMap.get(json); } const hash = A2(${packageName}$Vendor$Murmur3$hashString, 0, json); contextHashMap.set(json, hash); return hash; }` } ]; } module.exports = { optimize };