@inlang/sdk
Advanced tools
Comparing version 0.9.0 to 0.10.0
@@ -0,16 +1,29 @@ | ||
import type { ValueError } from "@sinclair/typebox/errors"; | ||
export declare class ProjectSettingsInvalidError extends Error { | ||
constructor(message: string, options: ErrorOptions); | ||
constructor(options: { | ||
errors: ValueError[]; | ||
}); | ||
} | ||
export declare class ProjectSettingsFileJSONSyntaxError extends Error { | ||
constructor(message: string, options: ErrorOptions); | ||
constructor(options: { | ||
cause: ErrorOptions["cause"]; | ||
path: string; | ||
}); | ||
} | ||
export declare class ProjectSettingsFileNotFoundError extends Error { | ||
constructor(message: string, options: ErrorOptions); | ||
constructor(options: { | ||
cause?: ErrorOptions["cause"]; | ||
path: string; | ||
}); | ||
} | ||
export declare class PluginSaveMessagesError extends Error { | ||
constructor(message: string, options: ErrorOptions); | ||
constructor(options: { | ||
cause: ErrorOptions["cause"]; | ||
}); | ||
} | ||
export declare class PluginLoadMessagesError extends Error { | ||
constructor(message: string, options: ErrorOptions); | ||
constructor(options: { | ||
cause: ErrorOptions["cause"]; | ||
}); | ||
} | ||
//# sourceMappingURL=errors.d.ts.map |
export class ProjectSettingsInvalidError extends Error { | ||
constructor(message, options) { | ||
super(message, options); | ||
constructor(options) { | ||
super(`The project settings are invalid:\n\n${options.errors | ||
.map((error) => `The value of "${error.path}" is invalid:\n\n${error.message}`) | ||
.join("\n")}`); | ||
this.name = "ProjectSettingsInvalidError"; | ||
@@ -8,4 +10,4 @@ } | ||
export class ProjectSettingsFileJSONSyntaxError extends Error { | ||
constructor(message, options) { | ||
super(message, options); | ||
constructor(options) { | ||
super(`The settings file at "${options.path}" is not a valid JSON file:\n\n${options.cause}`, options); | ||
this.name = "ProjectSettingsFileJSONSyntaxError"; | ||
@@ -15,4 +17,4 @@ } | ||
export class ProjectSettingsFileNotFoundError extends Error { | ||
constructor(message, options) { | ||
super(message, options); | ||
constructor(options) { | ||
super(`The file at "${options.path}" could not be read. Does the file exists?`, options); | ||
this.name = "ProjectSettingsFileNotFoundError"; | ||
@@ -22,4 +24,4 @@ } | ||
export class PluginSaveMessagesError extends Error { | ||
constructor(message, options) { | ||
super(message, options); | ||
constructor(options) { | ||
super(`An error occured in saveMessages() caused by ${options.cause}.`, options); | ||
this.name = "PluginSaveMessagesError"; | ||
@@ -29,6 +31,6 @@ } | ||
export class PluginLoadMessagesError extends Error { | ||
constructor(message, options) { | ||
super(message, options); | ||
constructor(options) { | ||
super(`An error occured in loadMessages() caused by ${options.cause}.`, options); | ||
this.name = "PluginLoadMessagesError"; | ||
} | ||
} |
@@ -49,3 +49,3 @@ import { resolveModules } from "./resolve-modules/index.js"; | ||
} | ||
throw new Error("unhandled"); | ||
throw new Error("Unhandled error in setSettings. This is an internal bug. Please file an issue."); | ||
} | ||
@@ -87,3 +87,3 @@ }; | ||
}) | ||
.catch((err) => markInitAsFailed(new PluginLoadMessagesError("Error in load messages", { cause: err }))); | ||
.catch((err) => markInitAsFailed(new PluginLoadMessagesError({ cause: err }))); | ||
}); | ||
@@ -127,3 +127,3 @@ // -- installed items ---------------------------------------------------- | ||
catch (err) { | ||
throw new PluginSaveMessagesError("Error in saving messages", { | ||
throw new PluginSaveMessagesError({ | ||
cause: err, | ||
@@ -166,9 +166,11 @@ }); | ||
if (settingsFileError) | ||
throw new ProjectSettingsFileNotFoundError(`Could not locate settings file in (${args.settingsFilePath}).`, { | ||
throw new ProjectSettingsFileNotFoundError({ | ||
cause: settingsFileError, | ||
path: args.settingsFilePath, | ||
}); | ||
const json = tryCatch(() => JSON.parse(settingsFile)); | ||
if (json.error) { | ||
throw new ProjectSettingsFileJSONSyntaxError(`The settings is not a valid JSON file.`, { | ||
throw new ProjectSettingsFileJSONSyntaxError({ | ||
cause: json.error, | ||
path: args.settingsFilePath, | ||
}); | ||
@@ -183,4 +185,4 @@ } | ||
if (typeErrors.length > 0) { | ||
throw new ProjectSettingsInvalidError(`The settings is invalid according to the schema.`, { | ||
cause: typeErrors, | ||
throw new ProjectSettingsInvalidError({ | ||
errors: typeErrors, | ||
}); | ||
@@ -187,0 +189,0 @@ } |
@@ -0,5 +1,6 @@ | ||
import type { ValueError } from "@sinclair/typebox/errors"; | ||
export * from "./plugins/errors.js"; | ||
export * from "./message-lint-rules/errors.js"; | ||
export declare class ModuleError extends Error { | ||
readonly Module: string; | ||
readonly module: string; | ||
constructor(message: string, options: { | ||
@@ -14,3 +15,3 @@ module: string; | ||
export declare class ModuleHasNoExportsError extends ModuleError { | ||
constructor(message: string, options: { | ||
constructor(options: { | ||
module: string; | ||
@@ -24,3 +25,3 @@ cause?: Error; | ||
export declare class ModuleImportError extends ModuleError { | ||
constructor(message: string, options: { | ||
constructor(options: { | ||
module: string; | ||
@@ -31,7 +32,7 @@ cause: Error; | ||
export declare class ModuleExportIsInvalidError extends ModuleError { | ||
constructor(message: string, options: { | ||
constructor(options: { | ||
module: string; | ||
cause?: Error; | ||
errors: ValueError[]; | ||
}); | ||
} | ||
//# sourceMappingURL=errors.d.ts.map |
export * from "./plugins/errors.js"; | ||
export * from "./message-lint-rules/errors.js"; | ||
export class ModuleError extends Error { | ||
Module; | ||
module; | ||
constructor(message, options) { | ||
super(message); | ||
this.name = "ModuleError"; | ||
this.Module = options.module; | ||
this.module = options.module; | ||
this.cause = options.cause; | ||
@@ -16,4 +16,4 @@ } | ||
export class ModuleHasNoExportsError extends ModuleError { | ||
constructor(message, options) { | ||
super(message, options); | ||
constructor(options) { | ||
super(`Module "${module}" has no exports. Every module must have an "export default".`, options); | ||
this.name = "ModuleHasNoExportsError"; | ||
@@ -26,4 +26,4 @@ } | ||
export class ModuleImportError extends ModuleError { | ||
constructor(message, options) { | ||
super(message, options); | ||
constructor(options) { | ||
super(`Couldn't import the plugin "${module}":\n\n${options.cause}`, options); | ||
this.name = "ModuleImportError"; | ||
@@ -33,6 +33,8 @@ } | ||
export class ModuleExportIsInvalidError extends ModuleError { | ||
constructor(message, options) { | ||
super(message, options); | ||
constructor(options) { | ||
super(`The export(s) of "${module}" are invalid:\n\n${options.errors | ||
.map((error) => `Path "${error.path}" with value "${error.value}": "${error.message}"`) | ||
.join("\n")}`, options); | ||
this.name = "ModuleExportIsInvalidError"; | ||
} | ||
} |
@@ -30,5 +30,4 @@ import dedent from "dedent"; | ||
catch (error) { | ||
let message = `Error while importing ${uri}: ${error?.message ?? "Unknown error"}`; | ||
if (error instanceof SyntaxError && uri.includes("jsdelivr")) { | ||
message += dedent `\n\n | ||
error.message += dedent `\n\n | ||
Are you sure that the file exists on JSDelivr? | ||
@@ -39,4 +38,4 @@ | ||
} | ||
throw new ModuleImportError(message, { module: uri, cause: error }); | ||
throw new ModuleImportError({ module: uri, cause: error }); | ||
} | ||
} |
@@ -0,8 +1,9 @@ | ||
import type { MessageLintRule } from "@inlang/message-lint-rule"; | ||
import type { ValueError } from "@sinclair/typebox/errors"; | ||
export declare class MessageLintRuleIsInvalidError extends Error { | ||
readonly module: string; | ||
constructor(message: string, options: { | ||
module: string; | ||
cause?: Error; | ||
constructor(options: { | ||
id: MessageLintRule["id"]; | ||
errors: ValueError[]; | ||
}); | ||
} | ||
//# sourceMappingURL=errors.d.ts.map |
export class MessageLintRuleIsInvalidError extends Error { | ||
module; | ||
constructor(message, options) { | ||
super(message); | ||
this.module = options.module; | ||
constructor(options) { | ||
super(`The message lint rule "${options.id}" is invalid:\n\n${options.errors.join("\n")}`); | ||
this.name = "MessageLintRuleIsInvalidError"; | ||
} | ||
} |
@@ -11,4 +11,6 @@ import { Value } from "@sinclair/typebox/value"; | ||
if (Value.Check(MessageLintRule, rule) === false) { | ||
result.errors.push(new MessageLintRuleIsInvalidError(`Couldn't parse lint rule "${rule.id}"`, { | ||
module: "not implemented", | ||
const errors = [...Value.Errors(MessageLintRule, rule)]; | ||
result.errors.push(new MessageLintRuleIsInvalidError({ | ||
id: rule.id, | ||
errors, | ||
})); | ||
@@ -15,0 +17,0 @@ continue; |
import type { Plugin } from "@inlang/plugin"; | ||
type PluginErrorOptions = { | ||
plugin: Plugin["id"] | undefined; | ||
} & Partial<Error>; | ||
declare class PluginError extends Error { | ||
readonly plugin: string; | ||
constructor(message: string, options: PluginErrorOptions); | ||
import type { ValueError } from "@sinclair/typebox/errors"; | ||
export declare class PluginHasInvalidIdError extends Error { | ||
constructor(options: { | ||
id: Plugin["id"]; | ||
}); | ||
} | ||
export declare class PluginHasInvalidIdError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions); | ||
export declare class PluginUsesReservedNamespaceError extends Error { | ||
constructor(options: { | ||
id: Plugin["id"]; | ||
}); | ||
} | ||
export declare class PluginUsesReservedNamespaceError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions); | ||
export declare class PluginHasInvalidSchemaError extends Error { | ||
constructor(options: { | ||
id: Plugin["id"]; | ||
errors: ValueError[]; | ||
}); | ||
} | ||
export declare class PluginHasInvalidSchemaError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions); | ||
export declare class PluginLoadMessagesFunctionAlreadyDefinedError extends Error { | ||
constructor(options: { | ||
id: Plugin["id"]; | ||
}); | ||
} | ||
export declare class PluginLoadMessagesFunctionAlreadyDefinedError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions); | ||
export declare class PluginSaveMessagesFunctionAlreadyDefinedError extends Error { | ||
constructor(options: { | ||
id: Plugin["id"]; | ||
}); | ||
} | ||
export declare class PluginSaveMessagesFunctionAlreadyDefinedError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions); | ||
export declare class PluginReturnedInvalidCustomApiError extends Error { | ||
constructor(options: { | ||
id: Plugin["id"]; | ||
cause: ErrorOptions["cause"]; | ||
}); | ||
} | ||
export declare class PluginReturnedInvalidCustomApiError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions); | ||
export declare class PluginsDoNotProvideLoadOrSaveMessagesError extends Error { | ||
constructor(); | ||
} | ||
export declare class PluginsDoNotProvideLoadOrSaveMessagesError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions); | ||
} | ||
export {}; | ||
//# sourceMappingURL=errors.d.ts.map |
@@ -1,51 +0,44 @@ | ||
class PluginError extends Error { | ||
plugin; | ||
constructor(message, options) { | ||
super(message); | ||
this.name = "PluginError"; | ||
this.plugin = options.plugin ?? "unknown"; | ||
} | ||
} | ||
export class PluginHasInvalidIdError extends PluginError { | ||
constructor(message, options) { | ||
super(message, options); | ||
export class PluginHasInvalidIdError extends Error { | ||
constructor(options) { | ||
super(`Plugin "${options.id}" has an invalid id. The id must:\n1) Start with "plugin."\n2) camelCase\n3) Contain a namespace.\nAn example would be "plugin.namespace.myPlugin".`); | ||
this.name = "PluginHasInvalidIdError"; | ||
} | ||
} | ||
export class PluginUsesReservedNamespaceError extends PluginError { | ||
constructor(message, options) { | ||
super(message, options); | ||
export class PluginUsesReservedNamespaceError extends Error { | ||
constructor(options) { | ||
super(`Plugin ${options.id} uses reserved namespace 'inlang'.`); | ||
this.name = "PluginUsesReservedNamespaceError"; | ||
} | ||
} | ||
export class PluginHasInvalidSchemaError extends PluginError { | ||
constructor(message, options) { | ||
super(message, options); | ||
export class PluginHasInvalidSchemaError extends Error { | ||
constructor(options) { | ||
super(`Plugin "${options.id}" has an invalid schema:\n\n${options.errors | ||
.map((error) => `Path "${error.path}" with value "${error.value}": "${error.message}"`) | ||
.join("\n")})}\n\nPlease refer to the documentation for the correct schema.`); | ||
this.name = "PluginHasInvalidSchemaError"; | ||
} | ||
} | ||
export class PluginLoadMessagesFunctionAlreadyDefinedError extends PluginError { | ||
constructor(message, options) { | ||
super(message, options); | ||
export class PluginLoadMessagesFunctionAlreadyDefinedError extends Error { | ||
constructor(options) { | ||
super(`Plugin "${options.id}" defines the \`loadMessages()\` function, but it was already defined by another plugin.\n\nInlang only allows one plugin to define the \`loadMessages()\` function.`); | ||
this.name = "PluginLoadMessagesFunctionAlreadyDefinedError"; | ||
} | ||
} | ||
export class PluginSaveMessagesFunctionAlreadyDefinedError extends PluginError { | ||
constructor(message, options) { | ||
super(message, options); | ||
export class PluginSaveMessagesFunctionAlreadyDefinedError extends Error { | ||
constructor(options) { | ||
super(`Plugin "${options.id}" defines the \`saveMessages()\` function, but it was already defined by another plugin.\n\nInlang only allows one plugin to define the \`saveMessages()\` function.`); | ||
this.name = "PluginSaveMessagesFunctionAlreadyDefinedError"; | ||
} | ||
} | ||
export class PluginReturnedInvalidCustomApiError extends PluginError { | ||
constructor(message, options) { | ||
super(message, options); | ||
export class PluginReturnedInvalidCustomApiError extends Error { | ||
constructor(options) { | ||
super(`Plugin "${options.id}" returned an invalid custom API:\n\n${options.cause}`, options); | ||
this.name = "PluginReturnedInvalidCustomApiError"; | ||
} | ||
} | ||
export class PluginsDoNotProvideLoadOrSaveMessagesError extends PluginError { | ||
constructor(message, options) { | ||
super(message, options); | ||
export class PluginsDoNotProvideLoadOrSaveMessagesError extends Error { | ||
constructor() { | ||
super(`No plugin provides a \`loadMessages()\` or \`saveMessages()\` function\n\nIn case no plugin threw an error, you likely forgot to add a plugin that handles the loading and saving of messages. Refer to the marketplace for available plugins https://inlang.com/marketplace.`); | ||
this.name = "PluginsDoNotProvideLoadOrSaveMessagesError"; | ||
options.plugin = "plugin.inlang.missing"; | ||
} | ||
} |
@@ -30,8 +30,8 @@ import { Plugin } from "@inlang/plugin"; | ||
if (hasInvalidId) { | ||
result.errors.push(new PluginHasInvalidIdError(`Plugin ${plugin.id} has an invalid id "${plugin.id}". It must be camelCase and contain a namespace like plugin.namespace.myPlugin.`, { plugin: plugin.id })); | ||
result.errors.push(new PluginHasInvalidIdError({ id: plugin.id })); | ||
} | ||
// -- USES RESERVED NAMESPACE -- | ||
if (plugin.id.includes("inlang") && !whitelistedPlugins.includes(plugin.id)) { | ||
result.errors.push(new PluginUsesReservedNamespaceError(`Plugin ${plugin.id} uses reserved namespace 'inlang'.`, { | ||
plugin: plugin.id, | ||
result.errors.push(new PluginUsesReservedNamespaceError({ | ||
id: plugin.id, | ||
})); | ||
@@ -41,5 +41,5 @@ } | ||
if (errors.length > 0) { | ||
result.errors.push(new PluginHasInvalidSchemaError(`Plugin ${plugin.id} uses an invalid schema. Please check the documentation for the correct Plugin type.`, { | ||
plugin: plugin.id, | ||
cause: errors, | ||
result.errors.push(new PluginHasInvalidSchemaError({ | ||
id: plugin.id, | ||
errors: errors, | ||
})); | ||
@@ -49,6 +49,6 @@ } | ||
if (typeof plugin.loadMessages === "function" && result.data.loadMessages !== undefined) { | ||
result.errors.push(new PluginLoadMessagesFunctionAlreadyDefinedError(`Plugin ${plugin.id} defines the loadMessages function, but it was already defined by another plugin.`, { plugin: plugin.id })); | ||
result.errors.push(new PluginLoadMessagesFunctionAlreadyDefinedError({ id: plugin.id })); | ||
} | ||
if (typeof plugin.saveMessages === "function" && result.data.saveMessages !== undefined) { | ||
result.errors.push(new PluginSaveMessagesFunctionAlreadyDefinedError(`Plugin ${plugin.id} defines the saveMessages function, but it was already defined by another plugin.`, { plugin: plugin.id })); | ||
result.errors.push(new PluginSaveMessagesFunctionAlreadyDefinedError({ id: plugin.id })); | ||
} | ||
@@ -62,8 +62,9 @@ // --- ADD APP SPECIFIC API --- | ||
if (error) { | ||
// @ts-ignore | ||
delete error.stack; | ||
result.errors.push(error); // TODO: add correct error type | ||
result.errors.push(new PluginReturnedInvalidCustomApiError({ id: plugin.id, cause: error })); | ||
} | ||
if (typeof customApi !== "object") { | ||
result.errors.push(new PluginReturnedInvalidCustomApiError(`Plugin ${plugin.id} defines the addCustomApi function, but it does not return an object.`, { plugin: plugin.id, cause: error })); | ||
else if (typeof customApi !== "object") { | ||
result.errors.push(new PluginReturnedInvalidCustomApiError({ | ||
id: plugin.id, | ||
cause: new Error(`The return value must be an object. Received "${typeof customApi}".`), | ||
})); | ||
} | ||
@@ -102,5 +103,5 @@ } | ||
typeof result.data.saveMessages !== "function") { | ||
result.errors.push(new PluginsDoNotProvideLoadOrSaveMessagesError("It seems you did not install any plugin that handles messages. Please add one to make inlang work. See https://inlang.com/documentation/plugins/registry.", { plugin: undefined })); | ||
result.errors.push(new PluginsDoNotProvideLoadOrSaveMessagesError()); | ||
} | ||
return result; | ||
}; |
@@ -22,3 +22,3 @@ import { InlangModule } from "@inlang/module"; | ||
if (importedModule.error) { | ||
moduleErrors.push(new ModuleImportError(`Couldn't import the plugin "${module}"`, { | ||
moduleErrors.push(new ModuleImportError({ | ||
module: module, | ||
@@ -31,3 +31,3 @@ cause: importedModule.error, | ||
if (importedModule.data?.default === undefined) { | ||
moduleErrors.push(new ModuleHasNoExportsError(`Module "${module}" has no exports.`, { | ||
moduleErrors.push(new ModuleHasNoExportsError({ | ||
module: module, | ||
@@ -39,5 +39,6 @@ })); | ||
if (isValidModule === false) { | ||
const errors = [...ModuleCompiler.Errors(importedModule.data)].map((e) => `${e.path} ${e.message}`); | ||
moduleErrors.push(new ModuleExportIsInvalidError(`Module "${module}" is invalid: ` + errors.join("\n"), { | ||
const errors = [...ModuleCompiler.Errors(importedModule.data)]; | ||
moduleErrors.push(new ModuleExportIsInvalidError({ | ||
module: module, | ||
errors, | ||
})); | ||
@@ -44,0 +45,0 @@ continue; |
@@ -14,3 +14,3 @@ import { expect, it } from "vitest"; | ||
_import: () => { | ||
throw new ModuleImportError("Could not import", { | ||
throw new ModuleImportError({ | ||
module: settings.modules[0], | ||
@@ -78,3 +78,3 @@ cause: new Error("Could not import"), | ||
const _import = async () => { | ||
throw new ModuleImportError("Could not import", { | ||
throw new ModuleImportError({ | ||
module: settings.modules[0], | ||
@@ -81,0 +81,0 @@ cause: new Error(), |
@@ -12,4 +12,4 @@ import type { Pattern } from "@inlang/message"; | ||
} | { | ||
type: "VariableReference"; | ||
name: string; | ||
type: "VariableReference"; | ||
})[]; | ||
@@ -16,0 +16,0 @@ }[]; |
{ | ||
"name": "@inlang/sdk", | ||
"type": "module", | ||
"version": "0.9.0", | ||
"version": "0.10.0", | ||
"license": "Apache-2.0", | ||
@@ -6,0 +6,0 @@ "publishConfig": { |
@@ -0,4 +1,10 @@ | ||
import type { ValueError } from "@sinclair/typebox/errors" | ||
export class ProjectSettingsInvalidError extends Error { | ||
constructor(message: string, options: ErrorOptions) { | ||
super(message, options) | ||
constructor(options: { errors: ValueError[] }) { | ||
super( | ||
`The project settings are invalid:\n\n${options.errors | ||
.map((error) => `The value of "${error.path}" is invalid:\n\n${error.message}`) | ||
.join("\n")}` | ||
) | ||
this.name = "ProjectSettingsInvalidError" | ||
@@ -9,4 +15,7 @@ } | ||
export class ProjectSettingsFileJSONSyntaxError extends Error { | ||
constructor(message: string, options: ErrorOptions) { | ||
super(message, options) | ||
constructor(options: { cause: ErrorOptions["cause"]; path: string }) { | ||
super( | ||
`The settings file at "${options.path}" is not a valid JSON file:\n\n${options.cause}`, | ||
options | ||
) | ||
this.name = "ProjectSettingsFileJSONSyntaxError" | ||
@@ -17,4 +26,4 @@ } | ||
export class ProjectSettingsFileNotFoundError extends Error { | ||
constructor(message: string, options: ErrorOptions) { | ||
super(message, options) | ||
constructor(options: { cause?: ErrorOptions["cause"]; path: string }) { | ||
super(`The file at "${options.path}" could not be read. Does the file exists?`, options) | ||
this.name = "ProjectSettingsFileNotFoundError" | ||
@@ -25,4 +34,4 @@ } | ||
export class PluginSaveMessagesError extends Error { | ||
constructor(message: string, options: ErrorOptions) { | ||
super(message, options) | ||
constructor(options: { cause: ErrorOptions["cause"] }) { | ||
super(`An error occured in saveMessages() caused by ${options.cause}.`, options) | ||
this.name = "PluginSaveMessagesError" | ||
@@ -33,6 +42,6 @@ } | ||
export class PluginLoadMessagesError extends Error { | ||
constructor(message: string, options: ErrorOptions) { | ||
super(message, options) | ||
constructor(options: { cause: ErrorOptions["cause"] }) { | ||
super(`An error occured in loadMessages() caused by ${options.cause}.`, options) | ||
this.name = "PluginLoadMessagesError" | ||
} | ||
} |
@@ -76,3 +76,5 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
throw new Error("unhandled") | ||
throw new Error( | ||
"Unhandled error in setSettings. This is an internal bug. Please file an issue." | ||
) | ||
} | ||
@@ -124,5 +126,3 @@ } | ||
}) | ||
.catch((err) => | ||
markInitAsFailed(new PluginLoadMessagesError("Error in load messages", { cause: err })) | ||
) | ||
.catch((err) => markInitAsFailed(new PluginLoadMessagesError({ cause: err }))) | ||
}) | ||
@@ -183,3 +183,3 @@ | ||
} catch (err) { | ||
throw new PluginSaveMessagesError("Error in saving messages", { | ||
throw new PluginSaveMessagesError({ | ||
cause: err, | ||
@@ -237,8 +237,6 @@ }) | ||
if (settingsFileError) | ||
throw new ProjectSettingsFileNotFoundError( | ||
`Could not locate settings file in (${args.settingsFilePath}).`, | ||
{ | ||
cause: settingsFileError, | ||
} | ||
) | ||
throw new ProjectSettingsFileNotFoundError({ | ||
cause: settingsFileError, | ||
path: args.settingsFilePath, | ||
}) | ||
@@ -248,4 +246,5 @@ const json = tryCatch(() => JSON.parse(settingsFile!)) | ||
if (json.error) { | ||
throw new ProjectSettingsFileJSONSyntaxError(`The settings is not a valid JSON file.`, { | ||
throw new ProjectSettingsFileJSONSyntaxError({ | ||
cause: json.error, | ||
path: args.settingsFilePath, | ||
}) | ||
@@ -261,4 +260,4 @@ } | ||
if (typeErrors.length > 0) { | ||
throw new ProjectSettingsInvalidError(`The settings is invalid according to the schema.`, { | ||
cause: typeErrors, | ||
throw new ProjectSettingsInvalidError({ | ||
errors: typeErrors, | ||
}) | ||
@@ -265,0 +264,0 @@ } |
@@ -0,1 +1,2 @@ | ||
import type { ValueError } from "@sinclair/typebox/errors" | ||
export * from "./plugins/errors.js" | ||
@@ -5,7 +6,7 @@ export * from "./message-lint-rules/errors.js" | ||
export class ModuleError extends Error { | ||
public readonly Module: string | ||
public readonly module: string | ||
constructor(message: string, options: { module: string; cause?: Error }) { | ||
super(message) | ||
this.name = "ModuleError" | ||
this.Module = options.module | ||
this.module = options.module | ||
this.cause = options.cause | ||
@@ -19,4 +20,4 @@ } | ||
export class ModuleHasNoExportsError extends ModuleError { | ||
constructor(message: string, options: { module: string; cause?: Error }) { | ||
super(message, options) | ||
constructor(options: { module: string; cause?: Error }) { | ||
super(`Module "${module}" has no exports. Every module must have an "export default".`, options) | ||
this.name = "ModuleHasNoExportsError" | ||
@@ -30,4 +31,4 @@ } | ||
export class ModuleImportError extends ModuleError { | ||
constructor(message: string, options: { module: string; cause: Error }) { | ||
super(message, options) | ||
constructor(options: { module: string; cause: Error }) { | ||
super(`Couldn't import the plugin "${module}":\n\n${options.cause}`, options) | ||
this.name = "ModuleImportError" | ||
@@ -38,6 +39,11 @@ } | ||
export class ModuleExportIsInvalidError extends ModuleError { | ||
constructor(message: string, options: { module: string; cause?: Error }) { | ||
super(message, options) | ||
constructor(options: { module: string; errors: ValueError[] }) { | ||
super( | ||
`The export(s) of "${module}" are invalid:\n\n${options.errors | ||
.map((error) => `Path "${error.path}" with value "${error.value}": "${error.message}"`) | ||
.join("\n")}`, | ||
options | ||
) | ||
this.name = "ModuleExportIsInvalidError" | ||
} | ||
} |
@@ -53,5 +53,4 @@ import dedent from "dedent" | ||
} catch (error) { | ||
let message = `Error while importing ${uri}: ${(error as Error)?.message ?? "Unknown error"}` | ||
if (error instanceof SyntaxError && uri.includes("jsdelivr")) { | ||
message += dedent`\n\n | ||
error.message += dedent`\n\n | ||
Are you sure that the file exists on JSDelivr? | ||
@@ -62,4 +61,4 @@ | ||
} | ||
throw new ModuleImportError(message, { module: uri, cause: error as Error }) | ||
throw new ModuleImportError({ module: uri, cause: error as Error }) | ||
} | ||
} |
@@ -0,9 +1,9 @@ | ||
import type { MessageLintRule } from "@inlang/message-lint-rule" | ||
import type { ValueError } from "@sinclair/typebox/errors" | ||
export class MessageLintRuleIsInvalidError extends Error { | ||
public readonly module: string | ||
constructor(message: string, options: { module: string; cause?: Error }) { | ||
super(message) | ||
this.module = options.module | ||
constructor(options: { id: MessageLintRule["id"]; errors: ValueError[] }) { | ||
super(`The message lint rule "${options.id}" is invalid:\n\n${options.errors.join("\n")}`) | ||
this.name = "MessageLintRuleIsInvalidError" | ||
} | ||
} |
@@ -12,5 +12,7 @@ import { Value } from "@sinclair/typebox/value" | ||
if (Value.Check(MessageLintRule, rule) === false) { | ||
const errors = [...Value.Errors(MessageLintRule, rule)] | ||
result.errors.push( | ||
new MessageLintRuleIsInvalidError(`Couldn't parse lint rule "${rule.id}"`, { | ||
module: "not implemented", | ||
new MessageLintRuleIsInvalidError({ | ||
id: rule.id, | ||
errors, | ||
}) | ||
@@ -17,0 +19,0 @@ ) |
import type { Plugin } from "@inlang/plugin" | ||
import type { ValueError } from "@sinclair/typebox/errors" | ||
type PluginErrorOptions = { | ||
plugin: Plugin["id"] | undefined | ||
} & Partial<Error> | ||
class PluginError extends Error { | ||
public readonly plugin: string | ||
constructor(message: string, options: PluginErrorOptions) { | ||
super(message) | ||
this.name = "PluginError" | ||
this.plugin = options.plugin ?? "unknown" | ||
} | ||
} | ||
export class PluginHasInvalidIdError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions) { | ||
super(message, options) | ||
export class PluginHasInvalidIdError extends Error { | ||
constructor(options: { id: Plugin["id"] }) { | ||
super( | ||
`Plugin "${options.id}" has an invalid id. The id must:\n1) Start with "plugin."\n2) camelCase\n3) Contain a namespace.\nAn example would be "plugin.namespace.myPlugin".` | ||
) | ||
this.name = "PluginHasInvalidIdError" | ||
@@ -24,5 +13,5 @@ } | ||
export class PluginUsesReservedNamespaceError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions) { | ||
super(message, options) | ||
export class PluginUsesReservedNamespaceError extends Error { | ||
constructor(options: { id: Plugin["id"] }) { | ||
super(`Plugin ${options.id} uses reserved namespace 'inlang'.`) | ||
this.name = "PluginUsesReservedNamespaceError" | ||
@@ -32,5 +21,9 @@ } | ||
export class PluginHasInvalidSchemaError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions) { | ||
super(message, options) | ||
export class PluginHasInvalidSchemaError extends Error { | ||
constructor(options: { id: Plugin["id"]; errors: ValueError[] }) { | ||
super( | ||
`Plugin "${options.id}" has an invalid schema:\n\n${options.errors | ||
.map((error) => `Path "${error.path}" with value "${error.value}": "${error.message}"`) | ||
.join("\n")})}\n\nPlease refer to the documentation for the correct schema.` | ||
) | ||
this.name = "PluginHasInvalidSchemaError" | ||
@@ -40,5 +33,7 @@ } | ||
export class PluginLoadMessagesFunctionAlreadyDefinedError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions) { | ||
super(message, options) | ||
export class PluginLoadMessagesFunctionAlreadyDefinedError extends Error { | ||
constructor(options: { id: Plugin["id"] }) { | ||
super( | ||
`Plugin "${options.id}" defines the \`loadMessages()\` function, but it was already defined by another plugin.\n\nInlang only allows one plugin to define the \`loadMessages()\` function.` | ||
) | ||
this.name = "PluginLoadMessagesFunctionAlreadyDefinedError" | ||
@@ -48,5 +43,7 @@ } | ||
export class PluginSaveMessagesFunctionAlreadyDefinedError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions) { | ||
super(message, options) | ||
export class PluginSaveMessagesFunctionAlreadyDefinedError extends Error { | ||
constructor(options: { id: Plugin["id"] }) { | ||
super( | ||
`Plugin "${options.id}" defines the \`saveMessages()\` function, but it was already defined by another plugin.\n\nInlang only allows one plugin to define the \`saveMessages()\` function.` | ||
) | ||
this.name = "PluginSaveMessagesFunctionAlreadyDefinedError" | ||
@@ -56,5 +53,5 @@ } | ||
export class PluginReturnedInvalidCustomApiError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions) { | ||
super(message, options) | ||
export class PluginReturnedInvalidCustomApiError extends Error { | ||
constructor(options: { id: Plugin["id"]; cause: ErrorOptions["cause"] }) { | ||
super(`Plugin "${options.id}" returned an invalid custom API:\n\n${options.cause}`, options) | ||
this.name = "PluginReturnedInvalidCustomApiError" | ||
@@ -64,8 +61,9 @@ } | ||
export class PluginsDoNotProvideLoadOrSaveMessagesError extends PluginError { | ||
constructor(message: string, options: PluginErrorOptions) { | ||
super(message, options) | ||
export class PluginsDoNotProvideLoadOrSaveMessagesError extends Error { | ||
constructor() { | ||
super( | ||
`No plugin provides a \`loadMessages()\` or \`saveMessages()\` function\n\nIn case no plugin threw an error, you likely forgot to add a plugin that handles the loading and saving of messages. Refer to the marketplace for available plugins https://inlang.com/marketplace.` | ||
) | ||
this.name = "PluginsDoNotProvideLoadOrSaveMessagesError" | ||
options.plugin = "plugin.inlang.missing" | ||
} | ||
} |
@@ -45,8 +45,3 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
if (hasInvalidId) { | ||
result.errors.push( | ||
new PluginHasInvalidIdError( | ||
`Plugin ${plugin.id} has an invalid id "${plugin.id}". It must be camelCase and contain a namespace like plugin.namespace.myPlugin.`, | ||
{ plugin: plugin.id } | ||
) | ||
) | ||
result.errors.push(new PluginHasInvalidIdError({ id: plugin.id })) | ||
} | ||
@@ -57,8 +52,5 @@ | ||
result.errors.push( | ||
new PluginUsesReservedNamespaceError( | ||
`Plugin ${plugin.id} uses reserved namespace 'inlang'.`, | ||
{ | ||
plugin: plugin.id, | ||
} | ||
) | ||
new PluginUsesReservedNamespaceError({ | ||
id: plugin.id, | ||
}) | ||
) | ||
@@ -70,9 +62,6 @@ } | ||
result.errors.push( | ||
new PluginHasInvalidSchemaError( | ||
`Plugin ${plugin.id} uses an invalid schema. Please check the documentation for the correct Plugin type.`, | ||
{ | ||
plugin: plugin.id, | ||
cause: errors, | ||
} | ||
) | ||
new PluginHasInvalidSchemaError({ | ||
id: plugin.id, | ||
errors: errors, | ||
}) | ||
) | ||
@@ -83,17 +72,7 @@ } | ||
if (typeof plugin.loadMessages === "function" && result.data.loadMessages !== undefined) { | ||
result.errors.push( | ||
new PluginLoadMessagesFunctionAlreadyDefinedError( | ||
`Plugin ${plugin.id} defines the loadMessages function, but it was already defined by another plugin.`, | ||
{ plugin: plugin.id } | ||
) | ||
) | ||
result.errors.push(new PluginLoadMessagesFunctionAlreadyDefinedError({ id: plugin.id })) | ||
} | ||
if (typeof plugin.saveMessages === "function" && result.data.saveMessages !== undefined) { | ||
result.errors.push( | ||
new PluginSaveMessagesFunctionAlreadyDefinedError( | ||
`Plugin ${plugin.id} defines the saveMessages function, but it was already defined by another plugin.`, | ||
{ plugin: plugin.id } | ||
) | ||
) | ||
result.errors.push(new PluginSaveMessagesFunctionAlreadyDefinedError({ id: plugin.id })) | ||
} | ||
@@ -110,12 +89,9 @@ | ||
if (error) { | ||
// @ts-ignore | ||
delete error.stack | ||
result.errors.push(error as any) // TODO: add correct error type | ||
} | ||
if (typeof customApi !== "object") { | ||
result.errors.push(new PluginReturnedInvalidCustomApiError({ id: plugin.id, cause: error })) | ||
} else if (typeof customApi !== "object") { | ||
result.errors.push( | ||
new PluginReturnedInvalidCustomApiError( | ||
`Plugin ${plugin.id} defines the addCustomApi function, but it does not return an object.`, | ||
{ plugin: plugin.id, cause: error } | ||
) | ||
new PluginReturnedInvalidCustomApiError({ | ||
id: plugin.id, | ||
cause: new Error(`The return value must be an object. Received "${typeof customApi}".`), | ||
}) | ||
) | ||
@@ -167,8 +143,3 @@ } | ||
) { | ||
result.errors.push( | ||
new PluginsDoNotProvideLoadOrSaveMessagesError( | ||
"It seems you did not install any plugin that handles messages. Please add one to make inlang work. See https://inlang.com/documentation/plugins/registry.", | ||
{ plugin: undefined } | ||
) | ||
) | ||
result.errors.push(new PluginsDoNotProvideLoadOrSaveMessagesError()) | ||
} | ||
@@ -175,0 +146,0 @@ |
@@ -26,3 +26,3 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ | ||
_import: () => { | ||
throw new ModuleImportError("Could not import", { | ||
throw new ModuleImportError({ | ||
module: settings.modules[0]!, | ||
@@ -98,3 +98,3 @@ cause: new Error("Could not import"), | ||
const _import = async () => { | ||
throw new ModuleImportError("Could not import", { | ||
throw new ModuleImportError({ | ||
module: settings.modules[0]!, | ||
@@ -101,0 +101,0 @@ cause: new Error(), |
@@ -38,3 +38,3 @@ import type { ResolveModuleFunction } from "./types.js" | ||
moduleErrors.push( | ||
new ModuleImportError(`Couldn't import the plugin "${module}"`, { | ||
new ModuleImportError({ | ||
module: module, | ||
@@ -50,3 +50,3 @@ cause: importedModule.error as Error, | ||
moduleErrors.push( | ||
new ModuleHasNoExportsError(`Module "${module}" has no exports.`, { | ||
new ModuleHasNoExportsError({ | ||
module: module, | ||
@@ -61,8 +61,7 @@ }) | ||
if (isValidModule === false) { | ||
const errors = [...ModuleCompiler.Errors(importedModule.data)].map( | ||
(e) => `${e.path} ${e.message}` | ||
) | ||
const errors = [...ModuleCompiler.Errors(importedModule.data)] | ||
moduleErrors.push( | ||
new ModuleExportIsInvalidError(`Module "${module}" is invalid: ` + errors.join("\n"), { | ||
new ModuleExportIsInvalidError({ | ||
module: module, | ||
errors, | ||
}) | ||
@@ -69,0 +68,0 @@ ) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
335829
8783