markback 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- markback/linter.py +39 -0
- markback/types.py +44 -4
- {markback-0.1.1.dist-info → markback-0.1.2.dist-info}/METADATA +1 -1
- {markback-0.1.1.dist-info → markback-0.1.2.dist-info}/RECORD +7 -7
- {markback-0.1.1.dist-info → markback-0.1.2.dist-info}/WHEEL +0 -0
- {markback-0.1.1.dist-info → markback-0.1.2.dist-info}/entry_points.txt +0 -0
- {markback-0.1.1.dist-info → markback-0.1.2.dist-info}/licenses/LICENSE +0 -0
markback/linter.py
CHANGED
|
@@ -137,6 +137,42 @@ def lint_prior_exists(
|
|
|
137
137
|
return diagnostics
|
|
138
138
|
|
|
139
139
|
|
|
140
|
+
def lint_line_range(
|
|
141
|
+
record: Record,
|
|
142
|
+
record_idx: int,
|
|
143
|
+
) -> list[Diagnostic]:
|
|
144
|
+
"""Check if line ranges are valid (end >= start)."""
|
|
145
|
+
diagnostics: list[Diagnostic] = []
|
|
146
|
+
|
|
147
|
+
# Check @source line range
|
|
148
|
+
if record.source and record.source.start_line is not None:
|
|
149
|
+
if record.source.end_line is not None and record.source.end_line < record.source.start_line:
|
|
150
|
+
diagnostics.append(Diagnostic(
|
|
151
|
+
file=record._source_file,
|
|
152
|
+
line=record._start_line,
|
|
153
|
+
column=None,
|
|
154
|
+
severity=Severity.ERROR,
|
|
155
|
+
code=ErrorCode.E011,
|
|
156
|
+
message=f"Invalid line range in @source: end line {record.source.end_line} is less than start line {record.source.start_line}",
|
|
157
|
+
record_index=record_idx,
|
|
158
|
+
))
|
|
159
|
+
|
|
160
|
+
# Check @prior line range
|
|
161
|
+
if record.prior and record.prior.start_line is not None:
|
|
162
|
+
if record.prior.end_line is not None and record.prior.end_line < record.prior.start_line:
|
|
163
|
+
diagnostics.append(Diagnostic(
|
|
164
|
+
file=record._source_file,
|
|
165
|
+
line=record._start_line,
|
|
166
|
+
column=None,
|
|
167
|
+
severity=Severity.ERROR,
|
|
168
|
+
code=ErrorCode.E011,
|
|
169
|
+
message=f"Invalid line range in @prior: end line {record.prior.end_line} is less than start line {record.prior.start_line}",
|
|
170
|
+
record_index=record_idx,
|
|
171
|
+
))
|
|
172
|
+
|
|
173
|
+
return diagnostics
|
|
174
|
+
|
|
175
|
+
|
|
140
176
|
def lint_canonical_format(
|
|
141
177
|
records: list[Record],
|
|
142
178
|
original_text: str,
|
|
@@ -206,6 +242,9 @@ def lint_string(
|
|
|
206
242
|
result.diagnostics.extend(lint_source_exists(record, base_path, idx))
|
|
207
243
|
result.diagnostics.extend(lint_prior_exists(record, base_path, idx))
|
|
208
244
|
|
|
245
|
+
# Check line range validity
|
|
246
|
+
result.diagnostics.extend(lint_line_range(record, idx))
|
|
247
|
+
|
|
209
248
|
# Check canonical format
|
|
210
249
|
if check_canonical and result.records and not result.has_errors:
|
|
211
250
|
result.diagnostics.extend(lint_canonical_format(
|
markback/types.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Core types for MarkBack format."""
|
|
2
2
|
|
|
3
|
+
import re
|
|
3
4
|
from dataclasses import dataclass, field
|
|
4
5
|
from enum import Enum
|
|
5
6
|
from pathlib import Path
|
|
@@ -25,6 +26,7 @@ class ErrorCode(Enum):
|
|
|
25
26
|
E008 = "E008" # Unclosed quote in structured attribute value
|
|
26
27
|
E009 = "E009" # Empty feedback (nothing after <<< )
|
|
27
28
|
E010 = "E010" # Missing blank line before inline content
|
|
29
|
+
E011 = "E011" # Invalid line range (end < start)
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
class WarningCode(Enum):
|
|
@@ -76,29 +78,67 @@ class Diagnostic:
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
|
|
81
|
+
# Regex to parse line range from a path: path:start or path:start-end
|
|
82
|
+
_LINE_RANGE_PATTERN = re.compile(r'^(.+?):(\d+)(?:-(\d+))?$')
|
|
83
|
+
|
|
84
|
+
|
|
79
85
|
@dataclass
|
|
80
86
|
class SourceRef:
|
|
81
87
|
"""Reference to external content (file path or URI)."""
|
|
82
88
|
value: str
|
|
83
89
|
is_uri: bool = False
|
|
90
|
+
start_line: Optional[int] = None
|
|
91
|
+
end_line: Optional[int] = None
|
|
92
|
+
_path_only: str = ""
|
|
84
93
|
|
|
85
94
|
def __post_init__(self):
|
|
86
|
-
#
|
|
95
|
+
# Parse line range if present
|
|
96
|
+
self._parse_line_range()
|
|
97
|
+
|
|
98
|
+
# Determine if this is a URI or file path (using path without line range)
|
|
87
99
|
if not self.is_uri:
|
|
88
|
-
parsed = urlparse(self.
|
|
100
|
+
parsed = urlparse(self._path_only)
|
|
89
101
|
# Consider it a URI if it has a scheme that's not a Windows drive letter
|
|
90
102
|
self.is_uri = bool(parsed.scheme) and len(parsed.scheme) > 1
|
|
91
103
|
|
|
104
|
+
def _parse_line_range(self):
|
|
105
|
+
"""Parse optional line range from value."""
|
|
106
|
+
match = _LINE_RANGE_PATTERN.match(self.value)
|
|
107
|
+
if match:
|
|
108
|
+
self._path_only = match.group(1)
|
|
109
|
+
self.start_line = int(match.group(2))
|
|
110
|
+
if match.group(3):
|
|
111
|
+
self.end_line = int(match.group(3))
|
|
112
|
+
else:
|
|
113
|
+
# Single line reference: start and end are the same
|
|
114
|
+
self.end_line = self.start_line
|
|
115
|
+
else:
|
|
116
|
+
self._path_only = self.value
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def path(self) -> str:
|
|
120
|
+
"""Return path without line range."""
|
|
121
|
+
return self._path_only
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def line_range_str(self) -> Optional[str]:
|
|
125
|
+
"""Return formatted line range string, or None if no range."""
|
|
126
|
+
if self.start_line is None:
|
|
127
|
+
return None
|
|
128
|
+
if self.start_line == self.end_line:
|
|
129
|
+
return f":{self.start_line}"
|
|
130
|
+
return f":{self.start_line}-{self.end_line}"
|
|
131
|
+
|
|
92
132
|
def resolve(self, base_path: Optional[Path] = None) -> Path:
|
|
93
133
|
"""Resolve to a file path (relative paths resolved against base_path)."""
|
|
94
134
|
if self.is_uri:
|
|
95
|
-
parsed = urlparse(self.
|
|
135
|
+
parsed = urlparse(self._path_only)
|
|
96
136
|
if parsed.scheme == "file":
|
|
97
137
|
# file:// URI
|
|
98
138
|
return Path(parsed.path)
|
|
99
139
|
raise ValueError(f"Cannot resolve non-file URI to path: {self.value}")
|
|
100
140
|
|
|
101
|
-
path = Path(self.
|
|
141
|
+
path = Path(self._path_only)
|
|
102
142
|
if path.is_absolute():
|
|
103
143
|
return path
|
|
104
144
|
if base_path:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: markback
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: A compact, human-writable format for storing content paired with feedback/labels
|
|
5
5
|
Project-URL: Homepage, https://github.com/dandriscoll/markback
|
|
6
6
|
Project-URL: Repository, https://github.com/dandriscoll/markback
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
markback/__init__.py,sha256=B0-2dpUu5nkbnUI0hPz-x7PHiOl7M-tiRi6s3UCYJFk,1540
|
|
2
2
|
markback/cli.py,sha256=5wMk1OUG7W_voS9DxeFxRJrBTMabEdOK_s_o3Irxuu0,13639
|
|
3
3
|
markback/config.py,sha256=eTVhb7UwDER9FRYo8QUAvneLHSqXD2ZtLUgtBtnljUs,5455
|
|
4
|
-
markback/linter.py,sha256=
|
|
4
|
+
markback/linter.py,sha256=IctgPEFNfGDo5DcELdo0Ni3d7Dp0bIWtlDw61ccWDOQ,11210
|
|
5
5
|
markback/llm.py,sha256=ON5_2C6v4KIk7_aIceulfWjEEI6hmallaPlLv-1-s_o,4692
|
|
6
6
|
markback/parser.py,sha256=P7GRjlwhy8j6Tnub7XAqILtZ4pFdkfdHhB-aIjLVRYU,18881
|
|
7
|
-
markback/types.py,sha256=
|
|
7
|
+
markback/types.py,sha256=tFunBAoqUEVf9mi_4N1QwWmOsKt0nocZK7M7K_rybWg,10097
|
|
8
8
|
markback/workflow.py,sha256=zC1RUm1i1wgiciFDqUilJKJ0-bgInvctxhQ0h5WSdoQ,10485
|
|
9
9
|
markback/writer.py,sha256=3-LeupyuruGv4WZH9pV65hU4YDKuC5HgIIZ8YZ2SZnM,7896
|
|
10
|
-
markback-0.1.
|
|
11
|
-
markback-0.1.
|
|
12
|
-
markback-0.1.
|
|
13
|
-
markback-0.1.
|
|
14
|
-
markback-0.1.
|
|
10
|
+
markback-0.1.2.dist-info/METADATA,sha256=d_xMmpicyEYeakJ4hA8SsrlGgj5Qxpd6fMv7tKf-eaI,5133
|
|
11
|
+
markback-0.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
12
|
+
markback-0.1.2.dist-info/entry_points.txt,sha256=Bc9aXvtlPxVPuOJ9BWGngAVrkx5dMvRgujjVzXC-V5U,46
|
|
13
|
+
markback-0.1.2.dist-info/licenses/LICENSE,sha256=lLK1n13C_CXb0M10O-6itEIDY6dsXKutZYQH-09n6s0,1068
|
|
14
|
+
markback-0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|