(pathValue, prefix, errors)
| 215 | } |
| 216 | |
| 217 | function validateRelativePath(pathValue, prefix, errors) { |
| 218 | if (!isNonEmptyString(pathValue)) { |
| 219 | errors.push(`${prefix}: "source.path" must be a non-empty string when provided`); |
| 220 | return; |
| 221 | } |
| 222 | |
| 223 | if (pathValue === "/") { |
| 224 | return; |
| 225 | } |
| 226 | |
| 227 | const normalized = path.posix.normalize(pathValue); |
| 228 | const segments = pathValue.split("/"); |
| 229 | |
| 230 | if (pathValue.startsWith("/") || pathValue.startsWith("../") || normalized !== pathValue || segments.includes("..")) { |
| 231 | errors.push(`${prefix}: "source.path" must be a safe relative path inside the repository`); |
| 232 | } |
| 233 | |
| 234 | if (pathValue.includes("\\")) { |
| 235 | errors.push(`${prefix}: "source.path" must use forward slashes`); |
| 236 | } |
| 237 | |
| 238 | if (normalized === ".") { |
| 239 | errors.push(`${prefix}: "source.path" must be "/" for the repository root or a plugin root directory relative to the repository root`); |
| 240 | } |
| 241 | |
| 242 | if (path.posix.basename(normalized) === "plugin.json") { |
| 243 | errors.push( |
| 244 | `${prefix}: "source.path" must point to the plugin root directory, not the manifest file; relative to "source.path", expected one of ${formatExpectedPluginRootMessage()}` |
| 245 | ); |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | function validateImmutableRef(ref, prefix, errors) { |
| 250 | if (!isNonEmptyString(ref)) { |
no test coverage detected