1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use miette::Diagnostic;
use node_semver::SemverError;
use nom::error::{ContextError, ErrorKind, FromExternalError, ParseError};
use thiserror::Error;
use url::ParseError as UrlParseError;
#[derive(Debug, Error, Diagnostic)]
#[error("Error parsing package spec. {kind}")]
#[diagnostic(
code(package_spec::no_parse),
help("Please fix your spec. Go look up wherever they're documented idk.")
)]
pub struct PackageSpecError {
pub input: String,
pub offset: usize,
pub kind: SpecErrorKind,
}
impl PackageSpecError {
pub fn location(&self) -> (usize, usize) {
let prefix = &self.input.as_bytes()[..self.offset];
let line_number = bytecount::count(prefix, b'\n');
let line_begin = prefix
.iter()
.rev()
.position(|&b| b == b'\n')
.map(|pos| self.offset - pos)
.unwrap_or(0);
let line = self.input[line_begin..]
.lines()
.next()
.unwrap_or(&self.input[line_begin..])
.trim_end();
let column_number = self.input[self.offset..].as_ptr() as usize - line.as_ptr() as usize;
(line_number, column_number)
}
}
#[derive(Debug, Error)]
pub enum SpecErrorKind {
#[error("Found invalid characters: `{0}`")]
InvalidCharacters(String),
#[error("Drive letters on Windows can only be alphabetical. Got `{0}`.")]
InvalidDriveLetter(char),
#[error("Invalid git host `{0}`. Only github:, gitlab:, gist:, and bitbucket: are supported in shorthands.")]
InvalidGitHost(String),
#[error(transparent)]
SemverParseError(SemverError),
#[error(transparent)]
UrlParseError(UrlParseError),
#[error(transparent)]
GitHostParseError(Box<PackageSpecError>),
#[error("Failed to parse {0} component of semver string.")]
Context(&'static str),
#[error("Incomplete input to semver parser.")]
IncompleteInput,
#[error("An unspecified error occurred.")]
Other,
}
#[derive(Debug)]
pub(crate) struct SpecParseError<I> {
pub(crate) input: I,
pub(crate) context: Option<&'static str>,
pub(crate) kind: Option<SpecErrorKind>,
}
impl<I> ParseError<I> for SpecParseError<I> {
fn from_error_kind(input: I, _kind: nom::error::ErrorKind) -> Self {
Self {
input,
context: None,
kind: None,
}
}
fn append(_input: I, _kind: nom::error::ErrorKind, other: Self) -> Self {
other
}
}
impl<I> ContextError<I> for SpecParseError<I> {
fn add_context(_input: I, ctx: &'static str, mut other: Self) -> Self {
other.context = Some(ctx);
other
}
}
impl<'a> FromExternalError<&'a str, SpecParseError<&'a str>> for SpecParseError<&'a str> {
fn from_external_error(_input: &'a str, _kind: ErrorKind, e: SpecParseError<&'a str>) -> Self {
e
}
}
impl<'a> FromExternalError<&'a str, SemverError> for SpecParseError<&'a str> {
fn from_external_error(input: &'a str, _kind: ErrorKind, e: SemverError) -> Self {
SpecParseError {
input,
context: None,
kind: Some(SpecErrorKind::SemverParseError(e)),
}
}
}
impl<'a> FromExternalError<&'a str, UrlParseError> for SpecParseError<&'a str> {
fn from_external_error(input: &'a str, _kind: ErrorKind, e: UrlParseError) -> Self {
SpecParseError {
input,
context: None,
kind: Some(SpecErrorKind::UrlParseError(e)),
}
}
}
impl<'a> FromExternalError<&'a str, PackageSpecError> for SpecParseError<&'a str> {
fn from_external_error(input: &'a str, _kind: ErrorKind, e: PackageSpecError) -> Self {
SpecParseError {
input,
context: None,
kind: Some(SpecErrorKind::GitHostParseError(Box::new(e))),
}
}
}