{"record":{"id":"b1a56e22209271a7","repo":"denoland/deno","slug":"prefix-linter-plugin-name-must-start-and-end-wit","errorCode":null,"errorMessage":"${prefix}Linter plugin name must start and end with a lowercase letter.","messagePattern":"(.+?)Linter plugin name must start and end with a lowercase letter\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/js/40_lint.js","lineNumber":494,"sourceCode":"  // When the plugin was loaded from a specifier (i.e. `lint.plugins` in the\n  // config), prefix validation errors with it so the user knows which plugin\n  // is misbehaving instead of getting an anonymous error.\n  const prefix = typeof specifier === \"string\"\n    ? `Failed to load lint plugin '${specifier}': `\n    : \"\";\n  if (typeof plugin !== \"object\") {\n    throw new Error(`${prefix}Linter plugin must be an object`);\n  }\n  if (typeof plugin.name !== \"string\") {\n    throw new Error(`${prefix}Linter plugin name must be a string`);\n  }\n  if (!/^[a-z-]+$/.test(plugin.name)) {\n    throw new Error(\n      `${prefix}Linter plugin name must only contain lowercase letters (a-z) or hyphens (-).`,\n    );\n  }\n  if (plugin.name.startsWith(\"-\") || plugin.name.endsWith(\"-\")) {\n    throw new Error(\n      `${prefix}Linter plugin name must start and end with a lowercase letter.`,\n    );\n  }\n  if (plugin.name.includes(\"--\")) {\n    throw new Error(\n      `${prefix}Linter plugin name must not have consequtive hyphens.`,\n    );\n  }\n  if (typeof plugin.rules !== \"object\") {\n    throw new Error(`${prefix}Linter plugin rules must be an object`);\n  }\n  if (state.installedPlugins.has(plugin.name)) {\n    throw new Error(`Linter plugin ${plugin.name} has already been registered`);\n  }\n  state.plugins.push(plugin);\n  state.installedPlugins.add(plugin.name);\n\n  return {","sourceCodeStart":476,"sourceCodeEnd":512,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/cli/js/40_lint.js#L476-L512","documentation":"Thrown by installPlugin() in cli/js/40_lint.js when the plugin name passes the /^[a-z-]+$/ character check but begins or ends with a hyphen. Leading/trailing hyphens would produce rule ids like \"-plugin/rule\" and \"plugin-/rule\", so they are rejected to keep ids clean.","triggerScenarios":"A plugin `name` like \"-my-plugin\" or \"my-plugin-\". Only fires after the character-set check passes, so the name is otherwise lowercase/hyphen only but has an edge hyphen.","commonSituations":"Renaming a plugin with a scope-like prefix (\"-internal-plugin\") to mark it private; a typo adding a trailing hyphen while editing the name string.","solutions":["Remove the leading/trailing hyphen so the name starts and ends with a lowercase letter","If you wanted a namespace prefix, fold it into the name with an inner hyphen, e.g. \"internal-plugin\""],"exampleFix":"// before\nexport default { name: \"-internal-plugin\", rules: {} };\n\n// after\nexport default { name: \"internal-plugin\", rules: {} };","handlingStrategy":"validation","validationCode":"function assertNoEdgeHyphens(name) {\n  if (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n    throw new TypeError(`'${name}' must start and end with a lowercase letter`);\n  }\n}","typeGuard":"function hasNoEdgeHyphens(name) {\n  return !name.startsWith(\"-\") && !name.endsWith(\"-\");\n}","tryCatchPattern":null,"preventionTips":["Use one canonical construction like kebab-case of the npm/jsr package name","Lint your own plugin source with a naming rule or a simple test"],"tags":["lint","plugin","validation","naming"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}