feat: expose ability to intercept taglib errors

This commit is contained in:
Dylan Piercey 2023-02-28 16:14:40 -07:00 committed by Dylan Piercey
parent 7ddbeb00f6
commit 4fc38e8001
16 changed files with 154 additions and 54 deletions

View File

@ -0,0 +1,7 @@
---
"@marko/compiler": minor
"marko": minor
"@marko/translator-default": minor
---
Expose the ability to intercept errors from the taglib builder.

12
package-lock.json generated
View File

@ -8133,11 +8133,6 @@
"node": ">=0.4.0"
}
},
"node_modules/property-handlers": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/property-handlers/-/property-handlers-1.1.1.tgz",
"integrity": "sha512-bPlermJL6CETDwI6SxODyMzr1a0aXzbXpNGCW9SnsnetEMJdjon1mdgLbidSN7o47B2oqLOwXYzGyyIQHsQrmw=="
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@ -10502,7 +10497,6 @@
"htmljs-parser": "^5.1.5",
"jsesc": "^3.0.2",
"lasso-package-root": "^1.0.1",
"property-handlers": "^1.1.1",
"raptor-regexp": "^1.0.1",
"raptor-util": "^3.2.0",
"resolve-from": "^5.0.0",
@ -12209,7 +12203,6 @@
"htmljs-parser": "^5.1.5",
"jsesc": "^3.0.2",
"lasso-package-root": "^1.0.1",
"property-handlers": "^1.1.1",
"raptor-regexp": "^1.0.1",
"raptor-util": "^3.2.0",
"resolve-from": "^5.0.0",
@ -16740,11 +16733,6 @@
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
"property-handlers": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/property-handlers/-/property-handlers-1.1.1.tgz",
"integrity": "sha512-bPlermJL6CETDwI6SxODyMzr1a0aXzbXpNGCW9SnsnetEMJdjon1mdgLbidSN7o47B2oqLOwXYzGyyIQHsQrmw=="
},
"proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",

View File

@ -1,8 +1,9 @@
import { SourceMap } from "magic-string";
import { TaglibLookup } from "@marko/babel-utils";
import * as types from "./babel-types";
import Config from "./config";
export { type Config, types };
export { types };
export type Config = typeof import("./config")
type Dep = {
type: string;
@ -65,7 +66,8 @@ export namespace taglib {
export function register(id: string, props: { [x: string]: unknown }): void;
export function buildLookup(
dirname: string,
translator?: unknown
translator?: unknown,
onError?: (err: Error) => void
): TaglibLookup;
export function clearCaches(): void;
}

View File

@ -21,7 +21,6 @@
"htmljs-parser": "^5.1.5",
"jsesc": "^3.0.2",
"lasso-package-root": "^1.0.1",
"property-handlers": "^1.1.1",
"raptor-regexp": "^1.0.1",
"raptor-util": "^3.2.0",
"resolve-from": "^5.0.0",

View File

@ -8,7 +8,7 @@ import { parseMarko } from "./parser";
import { visitor as migrate } from "./plugins/migrate";
import { visitor as transform } from "./plugins/transform";
import { MarkoFile } from "./file";
import { curFS, setFS } from "../taglib/fs";
import taglibConfig from "../taglib/config";
import tryLoadTranslator from "../util/try-load-translator";
import shouldOptimize from "../util/should-optimize";
@ -49,21 +49,21 @@ export default (api, markoOpts) => {
curOpts = opts;
},
parserOverride(code) {
let prevFS = curFS;
setFS(markoOpts.fileSystem);
let prevFS = taglibConfig.fs;
taglibConfig.fs = markoOpts.fileSystem;
try {
const file = getMarkoFile(code, curOpts, markoOpts);
const finalAst = t.cloneNode(file.ast, true);
SOURCE_FILES.set(finalAst, file);
return finalAst;
} finally {
setFS(prevFS);
taglibConfig.fs = prevFS;
}
},
pre(file) {
let prevFS = curFS;
let prevFS = taglibConfig.fs;
taglibConfig.fs = markoOpts.fileSystem;
curOpts = undefined;
setFS(markoOpts.fileSystem);
try {
if (markoOpts.output === "source" || markoOpts.output === "migrate") {
return file;
@ -104,7 +104,7 @@ export default (api, markoOpts) => {
metadata.marko.watchFiles = metadata.marko.watchFiles.filter(unique);
file.path.scope.crawl(); // Ensure all scopes are accurate for subsequent babel plugins
} finally {
setFS(prevFS);
taglibConfig.fs = prevFS;
}
}
};

View File

@ -156,5 +156,5 @@ if (globalThis[MARKO_CONFIG_KEY]) {
export default config;
import { setFS } from "./taglib/fs";
setFS(config.fileSystem);
import taglibConfig from "./taglib/config";
taglibConfig.fs = config.fileSystem;

View File

@ -0,0 +1,6 @@
module.exports = {
fs: undefined,
onError: err => {
throw err;
}
};

View File

@ -1,7 +1,7 @@
"use strict";
var nodePath = require("path");
var resolveFrom = require("resolve-from").silent;
var taglibFS = require("../fs");
var taglibConfig = require("../config");
var taglibLoader = require("../loader");
var lassoPackageRoot = require("lasso-package-root");
var findCache = {};
@ -148,7 +148,7 @@ function excludePackage(name) {
function existsSync(file) {
try {
taglibFS.curFS.statSync(file);
taglibConfig.fs.statSync(file);
return true;
} catch (_) {
return false;

View File

@ -1,4 +0,0 @@
export let curFS;
export function setFS(fs) {
curFS = fs;
}

View File

@ -1,6 +1,7 @@
import loader from "./loader";
import finder from "./finder";
import Lookup from "./lookup";
import taglibConfig from "./config";
import tryLoadTranslator from "../util/try-load-translator";
export const excludeDir = finder.excludeDir;
@ -18,7 +19,7 @@ register("marko/html", markoHTMLTaglib);
register("marko/svg", markoSVGTaglib);
register("marko/math", markoMathTaglib);
export function buildLookup(dirname, requestedTranslator) {
export function buildLookup(dirname, requestedTranslator, onError) {
const translator = tryLoadTranslator(requestedTranslator);
if (!translator || !Array.isArray(translator.taglibs)) {
throw new Error(
@ -26,19 +27,35 @@ export function buildLookup(dirname, requestedTranslator) {
);
}
if (!loadedTranslatorsTaglibs.has(translator)) {
let taglibsForDir = loadedTranslatorsTaglibs.get(translator);
if (!taglibsForDir) {
loadedTranslatorsTaglibs.set(
translator,
translator.taglibs.map(([id, props]) => loadTaglib(id, props))
(taglibsForDir = registeredTaglibs.concat(
translator.taglibs.map(([id, props]) => loadTaglib(id, props))
))
);
}
const taglibsForDir = finder.find(
dirname,
registeredTaglibs.concat(loadedTranslatorsTaglibs.get(translator))
);
if (onError) {
const prevOnError = taglibConfig.onError;
taglibConfig.onError = onError;
try {
taglibsForDir = finder.find(dirname, taglibsForDir);
} catch (err) {
taglibConfig.onError(err);
} finally {
taglibConfig.onError = prevOnError;
}
} else {
taglibsForDir = finder.find(dirname, taglibsForDir);
}
const cacheKey = taglibsForDir.map(it => it.id).join();
const cacheKey = taglibsForDir
.map(it => it.id)
.sort()
.join();
let lookup = lookupCache[cacheKey];
if (!lookup) {

View File

@ -1,9 +1,9 @@
var taglibFS = require("../fs");
var taglibConfig = require("../config");
var stripJsonComments = require("strip-json-comments");
var fsReadOptions = { encoding: "utf8" };
exports.readFileSync = function (path) {
var json = String(taglibFS.curFS.readFileSync(path, fsReadOptions));
var json = String(taglibConfig.fs.readFileSync(path, fsReadOptions));
try {
var taglibProps = JSON.parse(stripJsonComments(json));

View File

@ -2,7 +2,7 @@
var assert = require("assert");
var raptorRegexp = require("raptor-regexp");
var propertyHandlers = require("property-handlers");
var propertyHandlers = require("./property-handlers");
var types = require("./types");
var createError = require("raptor-util/createError");
var hasOwnProperty = Object.prototype.hasOwnProperty;

View File

@ -2,11 +2,11 @@
var ok = require("assert").ok;
var resolveFrom = require("resolve-from").silent;
var propertyHandlers = require("property-handlers");
var propertyHandlers = require("./property-handlers");
var isObjectEmpty = require("raptor-util/isObjectEmpty");
var nodePath = require("path");
var createError = require("raptor-util/createError");
var taglibFS = require("../fs");
var taglibConfig = require("../config");
var types = require("./types");
var loaders = require("./loaders");
var markoModules = require("../../../modules");
@ -315,7 +315,7 @@ class TagLoader {
var path = nodePath.resolve(dirname, value);
try {
taglibFS.curFS.statSync(path);
taglibConfig.fs.statSync(path);
tag.template = path;
} catch (_) {
throw new Error('Template at path "' + path + '" does not exist.');

View File

@ -4,9 +4,9 @@ var ok = require("assert").ok;
var resolveFrom = require("resolve-from").silent;
var nodePath = require("path");
var types = require("./types");
var taglibFS = require("../fs");
var taglibFS = require("../config");
var scanTagsDir = require("./scanTagsDir");
var propertyHandlers = require("property-handlers");
var propertyHandlers = require("./property-handlers");
var jsonFileReader = require("./json-file-reader");
var DependencyChain = require("./DependencyChain");
var createError = require("raptor-util/createError");
@ -98,7 +98,7 @@ class TaglibLoader {
tagFilePath = nodePath.resolve(this.dirname, value);
try {
taglibFS.curFS.statSync(tagFilePath);
taglibFS.fs.statSync(tagFilePath);
} catch (_) {
throw new Error(
'Tag at path "' +

View File

@ -0,0 +1,85 @@
"use strict";
const { hasOwnProperty } = Object.prototype;
const taglibConfig = require("../config");
function removeDashes(str) {
return str.replace(/-([a-z])/g, function (match, lower) {
return lower.toUpperCase();
});
}
module.exports = function invokeHandlers(config, handlers, path) {
function error(message, cause) {
if (cause) {
if (cause.__propertyHandlers) {
throw cause;
}
message += ". Cause: " + (cause.stack || cause);
}
if (path) {
message += " (" + path + ")";
}
var e = new Error(message);
e.__propertyHandlers = true;
taglibConfig.onError(e);
}
if (!config) {
error('"config" argument is required');
}
if (typeof config !== "object") {
error("object expected");
}
for (var k in config) {
if (hasOwnProperty.call(config, k)) {
var value = config[k];
var keyNoDashes = removeDashes(k);
var handler = handlers[keyNoDashes];
var isDefaultHandler = false;
if (!handler) {
handler = handlers["*"];
isDefaultHandler = true;
}
if (!handler) {
var badProperty = JSON.stringify(k);
if (k !== keyNoDashes) {
badProperty += "/" + JSON.stringify(keyNoDashes);
}
error(
"Invalid option of " +
badProperty +
". Allowed: " +
Object.keys(handlers).join(", ")
);
}
try {
if (isDefaultHandler) {
if (handler.call(handlers, k, value) === false) {
error("Invalid option: " + k);
}
} else {
handler.call(handlers, value);
}
} catch (e) {
error('Error while applying option of "' + k + '"', e);
}
}
}
if (handlers._end) {
try {
handlers._end();
} catch (e) {
error("Error after applying properties", e);
}
}
};

View File

@ -1,7 +1,7 @@
"use strict";
const nodePath = require("path");
const taglibFS = require("../fs");
const taglibConfig = require("../config");
const jsonFileReader = require("./json-file-reader");
const tagDefFromCode = require("./tag-def-from-code");
const loaders = require("./loaders");
@ -48,7 +48,7 @@ function createDefaultTagDef() {
function getFileMap(dirname) {
let fileMap = {};
let files = taglibFS.curFS.readdirSync(dirname);
let files = taglibConfig.fs.readdirSync(dirname);
files.forEach(file => {
let extName = nodePath.extname(file);
@ -77,7 +77,7 @@ function getPath(filename, fileMap) {
function findAndSetFile(tagDef, tagDirname) {
try {
if (!taglibFS.curFS.statSync(tagDirname).isDirectory()) {
if (!taglibConfig.fs.statSync(tagDirname).isDirectory()) {
return;
}
} catch (_) {
@ -133,7 +133,7 @@ module.exports = function scanTagsDir(
}
dir = nodePath.resolve(tagsConfigDirname, dir);
let children = taglibFS.curFS.readdirSync(dir);
let children = taglibConfig.fs.readdirSync(dir);
for (let i = 0, len = children.length; i < len; i++) {
let childFilename = children[i];
@ -160,7 +160,7 @@ module.exports = function scanTagsDir(
let hasTagJson = false;
try {
taglibFS.curFS.statSync(tagJsonPath);
taglibConfig.fs.statSync(tagJsonPath);
hasTagJson = true;
// eslint-disable-next-line no-empty
} catch (_) {}
@ -191,7 +191,7 @@ module.exports = function scanTagsDir(
if (!hasTagJson && (tagDef.renderer || tagDef.template)) {
let templateCode = String(
taglibFS.curFS.readFileSync(
taglibConfig.fs.readFileSync(
tagDef.renderer || tagDef.template,
fsReadOptions
)