1use mago_span::HasSpan;
2use serde::Deserialize;
3use serde::Serialize;
4
5use mago_interner::StringIdentifier;
6use mago_span::Span;
7
8#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
9pub struct Document {
10 pub span: Span,
11 pub elements: Vec<Element>,
12}
13
14#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
15pub enum Element {
16 Text(Text),
17 Code(Code),
18 Tag(Tag),
19 Line(Span),
20 Annotation(Annotation),
21}
22
23#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
24pub struct Text {
25 pub span: Span,
26 pub segments: Vec<TextSegment>,
27}
28
29#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
30pub struct Code {
31 pub span: Span,
32 pub directives: Vec<StringIdentifier>,
33 pub content: StringIdentifier,
34}
35
36#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
37pub enum TextSegment {
38 Paragraph { span: Span, content: StringIdentifier },
39 InlineCode(Code),
40 InlineTag(Tag),
41}
42
43#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
44pub struct Annotation {
45 pub span: Span,
46 pub name: StringIdentifier,
47 pub arguments: Option<StringIdentifier>,
48}
49
50#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
51pub struct Tag {
52 pub span: Span,
53 pub name: StringIdentifier,
54 pub kind: TagKind,
55 pub description: StringIdentifier,
56 pub description_span: Span,
57}
58
59#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
60#[non_exhaustive]
61pub enum TagKind {
62 Abstract,
63 Access,
64 Author,
65 Category,
66 Copyright,
67 Deprecated,
68 Example,
69 Final,
70 FileSource,
71 Global,
72 Ignore,
73 Internal,
74 License,
75 Link,
76 Method,
77 Mixin,
78 Name,
79 Package,
80 Param,
81 Property,
82 PropertyRead,
83 PropertyWrite,
84 SealProperties,
85 NoSealProperties,
86 SealMethods,
87 NoSealMethods,
88 ReadOnly,
89 NoNamedArguments,
90 Api,
91 PsalmApi,
92 PsalmInheritors,
93 Return,
94 See,
95 Since,
96 Static,
97 StaticVar,
98 SubPackage,
99 Todo,
100 Tutorial,
101 Uses,
102 Var,
103 Throws,
104 Version,
105 ParamLaterInvokedCallable,
106 ParamImmediatelyInvokedCallable,
107 ParamClosureThis,
108 Extends,
109 Implements,
110 Use,
111 NotDeprecated,
112 PhpstanImpure,
113 PhpstanPure,
114 Pure,
115 Immutable,
116 InheritDoc,
117 ParamOut,
118 Assert,
119 AssertIfTrue,
120 AssertIfFalse,
121 ConsistentConstructor,
122 PsalmConsistentConstructor,
123 PsalmConsistentTemplates,
124 PsalmParamOut,
125 PsalmVar,
126 PsalmParam,
127 PsalmReturn,
128 PsalmProperty,
129 PsalmPropertyRead,
130 PsalmPropertyWrite,
131 PsalmMethod,
132 PsalmIgnoreVar,
133 PsalmSuppress,
134 PsalmAssert,
135 PsalmAssertIfTrue,
136 PsalmAssertIfFalse,
137 PsalmIfThisIs,
138 PsalmThisOut,
139 PsalmIgnoreNullableReturn,
140 PsalmIgnoreFalsableReturn,
141 PsalmSealProperties,
142 PsalmNoSealProperties,
143 PsalmSealMethods,
144 PsalmNoSealMethods,
145 PsalmInternal,
146 PsalmReadOnly,
147 PsalmMutationFree,
148 PsalmExternalMutationFree,
149 MutationFree,
150 ExternalMutationFree,
151 PsalmImmutable,
152 PsalmPure,
153 PsalmAllowPrivateMutation,
154 PsalmReadOnlyAllowPrivateMutation,
155 PsalmTrace,
156 PsalmCheckType,
157 PsalmCheckTypeExact,
158 PsalmTaintSource,
159 PsalmTaintSink,
160 PsalmTaintEscape,
161 PsalmTaintUnescape,
162 PsalmTaintSpecialize,
163 PsalmFlow,
164 PsalmType,
165 PsalmImportType,
166 PsalmRequireExtends,
167 PsalmRequireImplements,
168 PsalmIgnoreVariableProperty,
169 PsalmIgnoreVariableMethod,
170 PsalmYield,
171 PhpstanAssert,
172 PhpstanAssertIfTrue,
173 PhpstanAssertIfFalse,
174 PhpstanSelfOut,
175 PhpstanThisOut,
176 PhpstanRequireExtends,
177 PhpstanRequireImplements,
178 PhpstanParam,
179 PhpstanReturn,
180 PhpstanVar,
181 PhpstanReadOnly,
182 PhpstanImmutable,
183 Template,
184 TemplateInvariant,
185 TemplateCovariant,
186 TemplateContravariant,
187 PsalmTemplate,
188 PsalmTemplateInvariant,
189 PsalmTemplateCovariant,
190 PsalmTemplateContravariant,
191 PhpstanTemplate,
192 PhpstanTemplateInvariant,
193 PhpstanTemplateCovariant,
194 PhpstanTemplateContravariant,
195 Other,
196}
197
198#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
199pub enum TagVendor {
200 Phpstan,
201 Psalm,
202}
203
204impl Document {
205 pub fn get_tags(&self) -> impl Iterator<Item = &Tag> {
206 self.elements.iter().filter_map(|element| if let Element::Tag(tag) = element { Some(tag) } else { None })
207 }
208
209 pub fn get_tags_by_kind(&self, kind: TagKind) -> impl Iterator<Item = &Tag> {
210 self.get_tags().filter(move |tag| tag.kind == kind)
211 }
212}
213
214impl HasSpan for Document {
215 fn span(&self) -> Span {
216 self.span
217 }
218}
219
220impl TagKind {
221 pub fn get_vendor(&self) -> Option<TagVendor> {
225 match self {
226 Self::PsalmConsistentConstructor
227 | Self::PsalmConsistentTemplates
228 | Self::PsalmParamOut
229 | Self::PsalmVar
230 | Self::PsalmParam
231 | Self::PsalmReturn
232 | Self::PsalmProperty
233 | Self::PsalmPropertyRead
234 | Self::PsalmPropertyWrite
235 | Self::PsalmMethod
236 | Self::PsalmIgnoreVar
237 | Self::PsalmSuppress
238 | Self::PsalmAssert
239 | Self::PsalmAssertIfTrue
240 | Self::PsalmAssertIfFalse
241 | Self::PsalmIfThisIs
242 | Self::PsalmThisOut
243 | Self::PsalmIgnoreNullableReturn
244 | Self::PsalmIgnoreFalsableReturn
245 | Self::PsalmSealProperties
246 | Self::PsalmNoSealProperties
247 | Self::PsalmSealMethods
248 | Self::PsalmNoSealMethods
249 | Self::PsalmInternal
250 | Self::PsalmReadOnly
251 | Self::PsalmMutationFree
252 | Self::PsalmExternalMutationFree
253 | Self::PsalmImmutable
254 | Self::PsalmPure
255 | Self::PsalmAllowPrivateMutation
256 | Self::PsalmReadOnlyAllowPrivateMutation
257 | Self::PsalmTrace
258 | Self::PsalmCheckType
259 | Self::PsalmCheckTypeExact
260 | Self::PsalmTaintSource
261 | Self::PsalmTaintSink
262 | Self::PsalmTaintEscape
263 | Self::PsalmTaintUnescape
264 | Self::PsalmTaintSpecialize
265 | Self::PsalmFlow
266 | Self::PsalmType
267 | Self::PsalmImportType
268 | Self::PsalmRequireExtends
269 | Self::PsalmRequireImplements
270 | Self::PsalmIgnoreVariableProperty
271 | Self::PsalmIgnoreVariableMethod
272 | Self::PsalmYield
273 | Self::PsalmTemplate
274 | Self::PsalmTemplateInvariant
275 | Self::PsalmTemplateCovariant
276 | Self::PsalmTemplateContravariant => Some(TagVendor::Psalm),
277 Self::PhpstanAssert
278 | Self::PhpstanAssertIfTrue
279 | Self::PhpstanAssertIfFalse
280 | Self::PhpstanSelfOut
281 | Self::PhpstanThisOut
282 | Self::PhpstanRequireExtends
283 | Self::PhpstanRequireImplements
284 | Self::PhpstanTemplate
285 | Self::PhpstanTemplateInvariant
286 | Self::PhpstanTemplateCovariant
287 | Self::PhpstanTemplateContravariant
288 | Self::PhpstanParam
289 | Self::PhpstanReturn
290 | Self::PhpstanVar
291 | Self::PhpstanReadOnly
292 | Self::PhpstanImmutable => Some(TagVendor::Phpstan),
293 _ => None,
294 }
295 }
296
297 pub fn get_non_vendored_variant(&self) -> Option<TagKind> {
304 match self {
305 Self::PsalmConsistentConstructor => Some(Self::ConsistentConstructor),
306 Self::PsalmParamOut => Some(Self::ParamOut),
307 Self::PsalmVar => Some(Self::Var),
308 Self::PsalmParam => Some(Self::Param),
309 Self::PsalmReturn => Some(Self::Return),
310 Self::PsalmProperty => Some(Self::Property),
311 Self::PsalmPropertyRead => Some(Self::PropertyRead),
312 Self::PsalmPropertyWrite => Some(Self::PropertyWrite),
313 Self::PsalmMethod => Some(Self::Method),
314 Self::PsalmSealProperties => Some(Self::SealProperties),
315 Self::PsalmNoSealProperties => Some(Self::NoSealProperties),
316 Self::PsalmSealMethods => Some(Self::SealMethods),
317 Self::PsalmNoSealMethods => Some(Self::NoSealMethods),
318 Self::PsalmInternal => Some(Self::Internal),
319 Self::PsalmReadOnly => Some(Self::ReadOnly),
320 Self::PsalmImmutable => Some(Self::Immutable),
321 Self::PsalmPure => Some(Self::Pure),
322 Self::PhpstanParam => Some(Self::Param),
323 Self::PhpstanReturn => Some(Self::Return),
324 Self::PhpstanVar => Some(Self::Var),
325 Self::PhpstanReadOnly => Some(Self::ReadOnly),
326 Self::PhpstanImmutable => Some(Self::Immutable),
327 Self::PhpstanAssert | Self::PsalmAssert => Some(Self::Assert),
328 Self::PhpstanAssertIfTrue | Self::PsalmAssertIfTrue => Some(Self::AssertIfTrue),
329 Self::PhpstanAssertIfFalse | Self::PsalmAssertIfFalse => Some(Self::AssertIfFalse),
330 Self::PhpstanTemplate | Self::PsalmTemplate => Some(Self::Template),
331 Self::PhpstanTemplateInvariant | Self::PsalmTemplateInvariant => Some(Self::TemplateInvariant),
332 Self::PhpstanTemplateCovariant | Self::PsalmTemplateCovariant => Some(Self::TemplateCovariant),
333 Self::PhpstanTemplateContravariant | Self::PsalmTemplateContravariant => Some(Self::TemplateContravariant),
334 Self::PsalmMutationFree => Some(Self::MutationFree),
335 Self::PsalmExternalMutationFree => Some(Self::ExternalMutationFree),
336 _ => None,
337 }
338 }
339
340 pub fn is_repeatable(&self) -> bool {
341 matches!(
342 self,
343 Self::Author
344 | Self::Deprecated
345 | Self::Example
346 | Self::Ignore
347 | Self::Link
348 | Self::Method
349 | Self::Mixin
350 | Self::Package
351 | Self::Param
352 | Self::Property
353 | Self::PropertyRead
354 | Self::PropertyWrite
355 | Self::Return
356 | Self::See
357 | Self::Since
358 | Self::Throws
359 | Self::Uses
360 | Self::Var
361 )
362 }
363}
364
365impl<T> From<T> for TagKind
366where
367 T: AsRef<str>,
368{
369 fn from(value: T) -> Self {
370 match value.as_ref().to_ascii_lowercase().as_str() {
371 "abstract" => TagKind::Abstract,
372 "access" => TagKind::Access,
373 "author" => TagKind::Author,
374 "category" => TagKind::Category,
375 "copyright" => TagKind::Copyright,
376 "deprecated" => TagKind::Deprecated,
377 "example" => TagKind::Example,
378 "final" => TagKind::Final,
379 "filesource" => TagKind::FileSource,
380 "global" => TagKind::Global,
381 "ignore" => TagKind::Ignore,
382 "internal" => TagKind::Internal,
383 "license" => TagKind::License,
384 "link" => TagKind::Link,
385 "method" => TagKind::Method,
386 "mixin" => TagKind::Mixin,
387 "name" => TagKind::Name,
388 "package" => TagKind::Package,
389 "param" => TagKind::Param,
390 "property" => TagKind::Property,
391 "property-read" => TagKind::PropertyRead,
392 "propertyread" => TagKind::PropertyRead,
393 "property-write" => TagKind::PropertyWrite,
394 "propertywrite" => TagKind::PropertyWrite,
395 "sealproperties" => TagKind::SealProperties,
396 "seal-properties" => TagKind::SealProperties,
397 "nosealproperties" => TagKind::NoSealProperties,
398 "no-seal-properties" => TagKind::NoSealProperties,
399 "sealmethods" => TagKind::SealMethods,
400 "seal-methods" => TagKind::SealMethods,
401 "nosealmethods" => TagKind::NoSealMethods,
402 "no-seal-methods" => TagKind::NoSealMethods,
403 "readonly" => TagKind::ReadOnly,
404 "nonamedarguments" => TagKind::NoNamedArguments,
405 "no-named-arguments" => TagKind::NoNamedArguments,
406 "api" => TagKind::Api,
407 "psalm-api" => TagKind::PsalmApi,
408 "psalm-inheritors" => TagKind::PsalmInheritors,
409 "return" => TagKind::Return,
410 "see" => TagKind::See,
411 "since" => TagKind::Since,
412 "static" => TagKind::Static,
413 "staticvar" => TagKind::StaticVar,
414 "static-var" => TagKind::StaticVar,
415 "subpackage" => TagKind::SubPackage,
416 "sub-package" => TagKind::SubPackage,
417 "todo" => TagKind::Todo,
418 "tutorial" => TagKind::Tutorial,
419 "uses" => TagKind::Uses,
420 "var" => TagKind::Var,
421 "throws" => TagKind::Throws,
422 "version" => TagKind::Version,
423 "assert" => TagKind::Assert,
424 "assert-if-true" | "assertiftrue" => TagKind::AssertIfTrue,
425 "assert-if-false" | "assertiffalse" => TagKind::AssertIfFalse,
426 "param-later-invoked-callable" => TagKind::ParamLaterInvokedCallable,
427 "paramlaterinvokedcallable" => TagKind::ParamLaterInvokedCallable,
428 "param-immediately-invoked-callable" => TagKind::ParamImmediatelyInvokedCallable,
429 "paramimmediatelyinvokedcallable" => TagKind::ParamImmediatelyInvokedCallable,
430 "param-closure-this" => TagKind::ParamClosureThis,
431 "paramclosurethis" => TagKind::ParamClosureThis,
432 "extends" => TagKind::Extends,
433 "implements" => TagKind::Implements,
434 "use" => TagKind::Use,
435 "not-deprecated" => TagKind::NotDeprecated,
436 "notdeprecated" => TagKind::NotDeprecated,
437 "phpstan-impure" => TagKind::PhpstanImpure,
438 "phpstan-pure" => TagKind::PhpstanPure,
439 "pure" => TagKind::Pure,
440 "immutable" => TagKind::Immutable,
441 "inheritdoc" => TagKind::InheritDoc,
442 "inherit-doc" => TagKind::InheritDoc,
443 "param-out" => TagKind::ParamOut,
444 "psalm-param-out" => TagKind::PsalmParamOut,
445 "consistentconstructor" | "consistent-constructor" => TagKind::ConsistentConstructor,
446 "psalmconsistentconstructor" | "psalm-consistent-constructor" => TagKind::PsalmConsistentConstructor,
447 "psalmconsistenttemplates" | "psalm-consistent-templates" => TagKind::PsalmConsistentTemplates,
448 "psalm-var" => TagKind::PsalmVar,
449 "psalm-param" => TagKind::PsalmParam,
450 "psalm-return" => TagKind::PsalmReturn,
451 "psalm-property" => TagKind::PsalmProperty,
452 "psalm-property-read" => TagKind::PsalmPropertyRead,
453 "psalm-propertyread" => TagKind::PsalmPropertyRead,
454 "psalm-property-write" => TagKind::PsalmPropertyWrite,
455 "psalm-propertywrite" => TagKind::PsalmPropertyWrite,
456 "psalm-method" => TagKind::PsalmMethod,
457 "psalm-ignore-var" => TagKind::PsalmIgnoreVar,
458 "psalmignorevar" => TagKind::PsalmIgnoreVar,
459 "psalm-suppress" => TagKind::PsalmSuppress,
460 "psalm-assert" => TagKind::PsalmAssert,
461 "psalm-assert-if-true" => TagKind::PsalmAssertIfTrue,
462 "psalm-assertiftrue" => TagKind::PsalmAssertIfTrue,
463 "psalm-assert-if-false" => TagKind::PsalmAssertIfFalse,
464 "psalm-assertiffalse" => TagKind::PsalmAssertIfFalse,
465 "psalm-if-this-is" => TagKind::PsalmIfThisIs,
466 "psalmifthisis" => TagKind::PsalmIfThisIs,
467 "psalm-this-out" => TagKind::PsalmThisOut,
468 "psalmthisout" => TagKind::PsalmThisOut,
469 "psalm-ignore-nullable-return" => TagKind::PsalmIgnoreNullableReturn,
470 "psalmignorenullablereturn" => TagKind::PsalmIgnoreNullableReturn,
471 "psalm-ignore-falsable-return" => TagKind::PsalmIgnoreFalsableReturn,
472 "psalmignorefalsablereturn" => TagKind::PsalmIgnoreFalsableReturn,
473 "psalm-seal-properties" => TagKind::PsalmSealProperties,
474 "psalmsealproperties" => TagKind::PsalmSealProperties,
475 "psalm-no-seal-properties" => TagKind::PsalmNoSealProperties,
476 "psalmnosealproperties" => TagKind::PsalmNoSealProperties,
477 "psalm-seal-methods" => TagKind::PsalmSealMethods,
478 "psalmsealmethods" => TagKind::PsalmSealMethods,
479 "psalm-no-seal-methods" => TagKind::PsalmNoSealMethods,
480 "psalmnosealmethods" => TagKind::PsalmNoSealMethods,
481 "psalm-internal" => TagKind::PsalmInternal,
482 "psalm-readonly" => TagKind::PsalmReadOnly,
483 "psalm-mutation-free" | "psalmmutationfree" => TagKind::PsalmMutationFree,
484 "psalm-external-mutation-free" | "psalmexternalmutationfree" => TagKind::PsalmExternalMutationFree,
485 "mutation-free" | "mutationfree" => TagKind::MutationFree,
486 "external-mutation-free" | "externalmutationfree" => TagKind::ExternalMutationFree,
487 "psalm-immutable" => TagKind::PsalmImmutable,
488 "psalm-pure" => TagKind::PsalmPure,
489 "psalm-allow-private-mutation" => TagKind::PsalmAllowPrivateMutation,
490 "psalmallowprivatemutation" => TagKind::PsalmAllowPrivateMutation,
491 "psalm-readonly-allow-private-mutation" => TagKind::PsalmReadOnlyAllowPrivateMutation,
492 "psalmreadonlyallowprivatemutation" => TagKind::PsalmReadOnlyAllowPrivateMutation,
493 "psalm-trace" => TagKind::PsalmTrace,
494 "psalm-check-type" => TagKind::PsalmCheckType,
495 "psalmchecktype" => TagKind::PsalmCheckType,
496 "psalm-check-type-exact" => TagKind::PsalmCheckTypeExact,
497 "psalmchecktypeexact" => TagKind::PsalmCheckTypeExact,
498 "psalm-taint-source" => TagKind::PsalmTaintSource,
499 "psalmtaintsource" => TagKind::PsalmTaintSource,
500 "psalm-taint-sink" => TagKind::PsalmTaintSink,
501 "psalmtaintsink" => TagKind::PsalmTaintSink,
502 "psalm-taint-escape" => TagKind::PsalmTaintEscape,
503 "psalmtaintescape" => TagKind::PsalmTaintEscape,
504 "psalm-taint-unescape" => TagKind::PsalmTaintUnescape,
505 "psalmtaintunescape" => TagKind::PsalmTaintUnescape,
506 "psalm-taint-specialize" => TagKind::PsalmTaintSpecialize,
507 "psalmtaintspecialize" => TagKind::PsalmTaintSpecialize,
508 "psalm-flow" => TagKind::PsalmFlow,
509 "psalmflow" => TagKind::PsalmFlow,
510 "psalm-type" => TagKind::PsalmType,
511 "psalm-import-type" => TagKind::PsalmImportType,
512 "psalm-require-extends" => TagKind::PsalmRequireExtends,
513 "psalmrequireextends" => TagKind::PsalmRequireExtends,
514 "psalm-require-implements" => TagKind::PsalmRequireImplements,
515 "psalmrequireimplements" => TagKind::PsalmRequireImplements,
516 "psalm-ignore-variable-property" => TagKind::PsalmIgnoreVariableProperty,
517 "psalmignorevariableproperty" => TagKind::PsalmIgnoreVariableProperty,
518 "psalm-ignore-variable-method" => TagKind::PsalmIgnoreVariableMethod,
519 "psalmignorevariablemethod" => TagKind::PsalmIgnoreVariableMethod,
520 "psalm-yield" => TagKind::PsalmYield,
521 "phpstan-assert" => TagKind::PhpstanAssert,
522 "phpstan-assert-if-true" => TagKind::PhpstanAssertIfTrue,
523 "phpstan-assert-if-false" => TagKind::PhpstanAssertIfFalse,
524 "phpstan-self-out" => TagKind::PhpstanSelfOut,
525 "phpstan-this-out" => TagKind::PhpstanThisOut,
526 "phpstan-require-extends" => TagKind::PhpstanRequireExtends,
527 "phpstan-require-implements" => TagKind::PhpstanRequireImplements,
528 "template" => TagKind::Template,
529 "template-invariant" | "templateinvariant" => TagKind::TemplateInvariant,
530 "template-covariant" | "templatecovariant" => TagKind::TemplateCovariant,
531 "template-contravariant" | "templatecontravariant" => TagKind::TemplateContravariant,
532 "psalm-template" | "psalmtemplate" => TagKind::PsalmTemplate,
533 "psalm-template-invariant" | "psalmtemplateinvariant" => TagKind::PsalmTemplateInvariant,
534 "psalm-template-covariant" | "psalmtemplatecovariant" => TagKind::PsalmTemplateCovariant,
535 "psalm-template-contravariant" | "psalmtemplatecontravariant" => TagKind::PsalmTemplateContravariant,
536 "phpstan-template" | "phpstantemplate" => TagKind::PhpstanTemplate,
537 "phpstan-template-invariant" | "phpstantemplateinvariant" => TagKind::PhpstanTemplateInvariant,
538 "phpstan-template-covariant" | "phpstantemplatecovariant" => TagKind::PhpstanTemplateCovariant,
539 "phpstan-template-contravariant" | "phpstantemplatecontravariant" => TagKind::PhpstanTemplateContravariant,
540 "phpstan-param" => TagKind::PhpstanParam,
541 "phpstan-return" => TagKind::PhpstanReturn,
542 "phpstan-var" => TagKind::PhpstanVar,
543 "phpstan-readonly" => TagKind::PhpstanReadOnly,
544 "phpstan-immutable" => TagKind::PhpstanImmutable,
545 _ => TagKind::Other,
546 }
547 }
548}