maya-mel 0.1.2

Single-entry Autodesk Maya MEL parsing and analysis library.
Documentation
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
//! Detailed Maya fact model types.
//!
//! Most users can stay on [`crate::maya`] entry points and inspect
//! [`crate::maya::model::MayaTopLevelFacts`]. Reach for this module when you
//! need the full set of Maya-specific item, hybrid, promotion, or
//! selective-collection data types.

use mel_parser::{LightCommandSurface, ParseOptions};
use mel_sema::{CommandKind, CommandMode};
use mel_syntax::{SourceView, TextRange};

#[derive(Debug, Clone, PartialEq, Eq, Default)]
/// Top-level Maya facts collected from a full parse.
///
/// The result is intentionally coarse-grained: each top-level item is either a
/// proc, a command-style statement promoted into Maya-aware form, or an
/// unclassified statement span.
pub struct MayaTopLevelFacts {
    pub items: Vec<MayaTopLevelItem>,
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct MayaLightTopLevelFacts {
    pub items: Vec<MayaLightTopLevelItem>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum MayaSelectivePassthrough {
    #[default]
    TargetOnly,
    IncludeOtherCommands,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct MayaSelectiveOptions {
    pub passthrough: MayaSelectivePassthrough,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MayaTrackedSetAttrAttr {
    B,
    St,
    Stp,
    Ftn,
    Fn,
    F,
}

pub trait MayaSelectiveSetAttrSelector {
    fn classify(&self, attr_path: &str) -> Option<MayaTrackedSetAttrAttr>;
}

impl<F> MayaSelectiveSetAttrSelector for F
where
    F: Fn(&str) -> Option<MayaTrackedSetAttrAttr>,
{
    fn classify(&self, attr_path: &str) -> Option<MayaTrackedSetAttrAttr> {
        self(attr_path)
    }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct DefaultMayaSelectiveSetAttrSelector;

impl MayaSelectiveSetAttrSelector for DefaultMayaSelectiveSetAttrSelector {
    fn classify(&self, attr_path: &str) -> Option<MayaTrackedSetAttrAttr> {
        let suffix = attr_path.rsplit('.').next()?;
        match suffix {
            "b" => Some(MayaTrackedSetAttrAttr::B),
            "st" => Some(MayaTrackedSetAttrAttr::St),
            "stp" => Some(MayaTrackedSetAttrAttr::Stp),
            "ftn" => Some(MayaTrackedSetAttrAttr::Ftn),
            "fn" => Some(MayaTrackedSetAttrAttr::Fn),
            "f" => Some(MayaTrackedSetAttrAttr::F),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MayaSelectiveItem {
    Requires(MayaSelectiveRequires),
    File(MayaSelectiveFile),
    CreateNode(MayaSelectiveCreateNode),
    SetAttr(MayaSelectiveSetAttr),
    OtherCommand {
        head_range: TextRange,
        span: TextRange,
    },
}

pub trait MayaSelectiveItemSink {
    fn on_item(&mut self, item: MayaSelectiveItem);
}

impl<F> MayaSelectiveItemSink for F
where
    F: FnMut(MayaSelectiveItem),
{
    fn on_item(&mut self, item: MayaSelectiveItem) {
        self(item);
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaSelectiveRequires {
    pub head_range: TextRange,
    pub argument_ranges: Vec<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaSelectiveFile {
    pub head_range: TextRange,
    pub path_range: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaSelectiveCreateNode {
    pub head_range: TextRange,
    pub node_type_range: Option<TextRange>,
    pub name_range: Option<TextRange>,
    pub parent_range: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaSelectiveSetAttr {
    pub head_range: TextRange,
    pub attr_path_range: Option<TextRange>,
    pub type_name_range: Option<TextRange>,
    pub tracked_attr: Option<MayaTrackedSetAttrAttr>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MayaPromotionKind {
    FullParse,
    LightSynthesized,
    OpaqueTailPromoted,
    PolicyPromoted,
    CustomDeciderPromoted,
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum MayaPromotionPolicy {
    #[default]
    OpaqueTailOnly,
    ByCommandName(Vec<String>),
    Always,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaPromotionError {
    pub command_span: TextRange,
    pub head: Option<String>,
    pub message: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaPromotionDiagnostic {
    pub command_span: TextRange,
    pub head: Option<String>,
    pub attempted_kind: MayaPromotionKind,
    pub message: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaCommandValidationDiagnostic {
    pub command_span: TextRange,
    pub head: Option<String>,
    pub message: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct MayaHybridTopLevelReport {
    pub facts: MayaTopLevelFacts,
    pub promotion_diagnostics: Vec<MayaPromotionDiagnostic>,
    pub validation_diagnostics: Vec<MayaCommandValidationDiagnostic>,
}

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct MayaPromotionOptions {
    pub policy: MayaPromotionPolicy,
    pub parse_options: ParseOptions,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MayaPromotionCandidate<'a> {
    pub command: &'a LightCommandSurface,
    pub raw_head: &'a str,
    pub canonical_name: Option<&'a str>,
}

pub trait MayaPromotionDecider {
    fn should_promote(&self, candidate: MayaPromotionCandidate<'_>) -> bool;
}

impl<F> MayaPromotionDecider for F
where
    F: for<'a> Fn(MayaPromotionCandidate<'a>) -> bool,
{
    fn should_promote(&self, candidate: MayaPromotionCandidate<'_>) -> bool {
        self(candidate)
    }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct NoopPromotionDecider;

impl MayaPromotionDecider for NoopPromotionDecider {
    fn should_promote(&self, _: MayaPromotionCandidate<'_>) -> bool {
        false
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// A top-level item observed while collecting Maya facts from a full parse.
pub enum MayaTopLevelItem {
    Command(Box<MayaTopLevelCommand>),
    Proc {
        name: String,
        is_global: bool,
        span: TextRange,
    },
    Other {
        span: TextRange,
    },
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MayaLightTopLevelItem {
    Command(Box<MayaLightTopLevelCommand>),
    Proc {
        name: Option<String>,
        is_global: bool,
        span: TextRange,
    },
    Other {
        span: TextRange,
    },
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// Maya-specific view of a top-level command statement.
///
/// This keeps the original shell-like surface in [`Self::raw_items`] while also
/// attaching optional normalized and specialized forms.
pub struct MayaTopLevelCommand {
    pub head: String,
    pub captured: bool,
    pub raw_items: Vec<MayaRawShellItem>,
    pub normalized: Option<MayaNormalizedCommand>,
    pub specialized: Option<MayaSpecializedCommand>,
    pub promotion_kind: MayaPromotionKind,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightTopLevelCommand {
    pub head: String,
    pub captured: bool,
    pub prefix_items: Vec<MayaRawShellItem>,
    pub opaque_tail: Option<TextRange>,
    pub specialized: Option<MayaLightSpecializedCommand>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// Lossless raw shell item captured from a command-style invocation.
pub struct MayaRawShellItem {
    /// Surface classification for this shell item.
    pub kind: MayaRawShellItemKind,
    /// Lossless source span for the full raw item surface as it appeared in the command.
    pub span: TextRange,
    pub(crate) text_range: Option<TextRange>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// Surface classification for a raw shell item.
pub enum MayaRawShellItemKind {
    Flag,
    Numeric,
    BareWord,
    QuotedString,
    Variable,
    GroupedExpr,
    BraceList,
    VectorLiteral,
    Capture,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaPositionalArg {
    pub item: MayaRawShellItem,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaNormalizedFlag {
    pub source_range: TextRange,
    pub canonical_name: Option<String>,
    pub args: Vec<MayaPositionalArg>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightFlag {
    pub source_range: TextRange,
    pub canonical_name: Option<String>,
    pub args: Vec<MayaPositionalArg>,
    pub span: TextRange,
}

impl MayaRawShellItem {
    /// Returns the lexical text span used to derive [`Self::value_text`], when this item kind has one.
    ///
    /// This range is distinct from [`Self::span`]: `span` covers the full raw item surface,
    /// while `text_range` points at the slice that backs value extraction for literal-like words.
    #[must_use]
    pub fn text_range(&self) -> Option<TextRange> {
        self.text_range
    }

    /// Returns the lossless source text for the full raw item surface.
    #[must_use]
    pub fn source_text<'a>(&self, source: SourceView<'a>) -> &'a str {
        source.display_slice(self.span)
    }

    /// Returns the lexical value text for literal-like words.
    ///
    /// This accessor uses [`Self::text_range`] and may further normalize the sliced text by kind,
    /// such as stripping the surrounding quotes from quoted strings.
    #[must_use]
    pub fn value_text<'a>(&self, source: SourceView<'a>) -> Option<&'a str> {
        let text = source.slice(self.text_range?);
        match self.kind {
            MayaRawShellItemKind::Numeric | MayaRawShellItemKind::BareWord => Some(text),
            MayaRawShellItemKind::QuotedString => text
                .strip_prefix('"')
                .and_then(|text| text.strip_suffix('"')),
            MayaRawShellItemKind::Flag
            | MayaRawShellItemKind::Variable
            | MayaRawShellItemKind::GroupedExpr
            | MayaRawShellItemKind::BraceList
            | MayaRawShellItemKind::VectorLiteral
            | MayaRawShellItemKind::Capture => None,
        }
    }

    /// Returns the preferred consumer-facing text for this shell item.
    ///
    /// Literal-like words use [`Self::value_text`] so downstream consumers can read decoded
    /// values without stripping quotes manually. Other shell surfaces fall back to full
    /// source-preserving text.
    #[must_use]
    pub fn preferred_text<'a>(&self, source: SourceView<'a>) -> &'a str {
        self.value_text(source)
            .unwrap_or_else(|| self.source_text(source))
    }
}

impl MayaPositionalArg {
    #[must_use]
    pub fn preferred_text<'a>(&self, source: SourceView<'a>) -> &'a str {
        self.item.preferred_text(source)
    }
}

impl MayaNormalizedFlag {
    #[must_use]
    pub fn source_text<'a>(&self, source: SourceView<'a>) -> &'a str {
        source.display_slice(self.source_range)
    }

    #[must_use]
    pub fn preferred_name<'a>(&'a self, source: SourceView<'a>) -> &'a str {
        self.canonical_name
            .as_deref()
            .unwrap_or_else(|| self.source_text(source))
    }

    #[must_use]
    pub fn matches_name(&self, source: SourceView<'_>, canonical: &str, short: &str) -> bool {
        self.canonical_name.as_deref() == Some(canonical)
            || self.source_text(source) == short
            || self.source_text(source).trim_start_matches('-') == short.trim_start_matches('-')
    }
}

impl MayaLightFlag {
    #[must_use]
    pub fn source_text<'a>(&self, source: SourceView<'a>) -> &'a str {
        source.display_slice(self.source_range)
    }

    #[must_use]
    pub fn preferred_name<'a>(&'a self, source: SourceView<'a>) -> &'a str {
        self.canonical_name
            .as_deref()
            .unwrap_or_else(|| self.source_text(source))
    }

    #[must_use]
    pub fn matches_name(&self, source: SourceView<'_>, canonical: &str, short: &str) -> bool {
        self.canonical_name.as_deref() == Some(canonical)
            || self.source_text(source) == short
            || self.source_text(source).trim_start_matches('-') == short.trim_start_matches('-')
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MayaNormalizedCommandItem {
    Flag(MayaNormalizedFlag),
    Positional(MayaPositionalArg),
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// Generic normalized command representation before Maya-specific specialization.
pub struct MayaNormalizedCommand {
    pub head: String,
    pub(crate) head_range: TextRange,
    pub schema_name: String,
    pub kind: CommandKind,
    pub mode: CommandMode,
    pub items: Vec<MayaNormalizedCommandItem>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// Maya-specific structured command variants derived from a top-level command.
pub enum MayaSpecializedCommand {
    Requires(MayaRequiresCommand),
    CurrentUnit(MayaCurrentUnitCommand),
    FileInfo(MayaFileInfoCommand),
    CreateNode(MayaCreateNodeCommand),
    Rename(MayaRenameCommand),
    Select(MayaSelectCommand),
    SetAttr(MayaSetAttrCommand),
    AddAttr(Box<MayaAddAttrCommand>),
    ConnectAttr(MayaConnectAttrCommand),
    Relationship(MayaRelationshipCommand),
    File(MayaFileCommand),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MayaLightSpecializedCommand {
    Requires(MayaLightRequiresCommand),
    CurrentUnit(MayaLightCurrentUnitCommand),
    FileInfo(MayaLightFileInfoCommand),
    CreateNode(MayaLightCreateNodeCommand),
    Rename(MayaLightRenameCommand),
    Select(MayaLightSelectCommand),
    SetAttr(MayaLightSetAttrCommand),
    AddAttr(Box<MayaLightAddAttrCommand>),
    ConnectAttr(MayaLightConnectAttrCommand),
    Relationship(MayaLightRelationshipCommand),
    File(MayaLightFileCommand),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaRequiresCommand {
    pub plugin_name: Option<MayaRawShellItem>,
    pub plugin_version: Option<MayaRawShellItem>,
    pub option_items: Vec<MayaRawShellItem>,
    pub requirements: Vec<MayaRawShellItem>,
    pub flags: Vec<MayaNormalizedFlag>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightRequiresCommand {
    pub plugin_name: Option<MayaRawShellItem>,
    pub plugin_version: Option<MayaRawShellItem>,
    pub option_items: Vec<MayaRawShellItem>,
    pub requirements: Vec<MayaRawShellItem>,
    pub flags: Vec<MayaLightFlag>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaCurrentUnitCommand {
    pub linear: Option<MayaRawShellItem>,
    pub angle: Option<MayaRawShellItem>,
    pub time: Option<MayaRawShellItem>,
    pub flags: Vec<MayaNormalizedFlag>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightCurrentUnitCommand {
    pub linear: Option<MayaRawShellItem>,
    pub angle: Option<MayaRawShellItem>,
    pub time: Option<MayaRawShellItem>,
    pub flags: Vec<MayaLightFlag>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaFileInfoCommand {
    pub key: Option<MayaRawShellItem>,
    pub value: Option<MayaRawShellItem>,
    pub flags: Vec<MayaNormalizedFlag>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightFileInfoCommand {
    pub key: Option<MayaRawShellItem>,
    pub value: Option<MayaRawShellItem>,
    pub flags: Vec<MayaLightFlag>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaCreateNodeCommand {
    pub node_type: Option<MayaRawShellItem>,
    pub name: Option<MayaRawShellItem>,
    pub parent: Option<MayaRawShellItem>,
    pub shared: bool,
    pub flags: Vec<MayaNormalizedFlag>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightCreateNodeCommand {
    pub node_type: Option<MayaRawShellItem>,
    pub name: Option<MayaRawShellItem>,
    pub parent: Option<MayaRawShellItem>,
    pub shared: bool,
    pub flags: Vec<MayaLightFlag>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaRenameCommand {
    pub uuid: Option<MayaRawShellItem>,
    pub source: Option<MayaRawShellItem>,
    pub target: Option<MayaRawShellItem>,
    pub flags: Vec<MayaNormalizedFlag>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightRenameCommand {
    pub uuid: Option<MayaRawShellItem>,
    pub source: Option<MayaRawShellItem>,
    pub target: Option<MayaRawShellItem>,
    pub flags: Vec<MayaLightFlag>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaSelectCommand {
    pub no_expand: bool,
    pub targets: Vec<MayaRawShellItem>,
    pub flags: Vec<MayaNormalizedFlag>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightSelectCommand {
    pub no_expand: bool,
    pub targets: Vec<MayaRawShellItem>,
    pub flags: Vec<MayaLightFlag>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaSetAttrCommand {
    pub attr_path: Option<MayaRawShellItem>,
    pub type_name: Option<MayaRawShellItem>,
    pub value_kind: MayaSetAttrValueKind,
    pub values: Vec<MayaRawShellItem>,
    pub flags: Vec<MayaNormalizedFlag>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightSetAttrCommand {
    pub attr_path: Option<MayaRawShellItem>,
    pub type_name: Option<MayaRawShellItem>,
    pub value_kind: MayaSetAttrValueKind,
    pub prefix_values: Vec<MayaRawShellItem>,
    pub flags: Vec<MayaLightFlag>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MayaSetAttrValueKind {
    TypedNumbers,
    String,
    StringArray,
    Int32Array,
    ComponentList,
    OpaqueTyped,
    MatrixXform,
    DataReferenceEdits,
    Unknown,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaAddAttrCommand {
    pub short_name: Option<MayaRawShellItem>,
    pub long_name: Option<MayaRawShellItem>,
    pub parent: Option<MayaRawShellItem>,
    pub number_of_children: Option<MayaRawShellItem>,
    pub nice_name: Option<MayaRawShellItem>,
    pub default_value: Option<MayaRawShellItem>,
    pub min_value: Option<MayaRawShellItem>,
    pub max_value: Option<MayaRawShellItem>,
    pub soft_min_value: Option<MayaRawShellItem>,
    pub soft_max_value: Option<MayaRawShellItem>,
    pub enum_name: Option<MayaRawShellItem>,
    pub attribute_type: Option<MayaRawShellItem>,
    pub data_type: Option<MayaRawShellItem>,
    pub flags: Vec<MayaNormalizedFlag>,
    pub tail: Vec<MayaRawShellItem>,
    pub tail_kind: MayaAddAttrTailKind,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightAddAttrCommand {
    pub short_name: Option<MayaRawShellItem>,
    pub long_name: Option<MayaRawShellItem>,
    pub parent: Option<MayaRawShellItem>,
    pub number_of_children: Option<MayaRawShellItem>,
    pub nice_name: Option<MayaRawShellItem>,
    pub default_value: Option<MayaRawShellItem>,
    pub min_value: Option<MayaRawShellItem>,
    pub max_value: Option<MayaRawShellItem>,
    pub soft_min_value: Option<MayaRawShellItem>,
    pub soft_max_value: Option<MayaRawShellItem>,
    pub enum_name: Option<MayaRawShellItem>,
    pub attribute_type: Option<MayaRawShellItem>,
    pub data_type: Option<MayaRawShellItem>,
    pub flags: Vec<MayaLightFlag>,
    pub tail: Vec<MayaRawShellItem>,
    pub tail_kind: MayaAddAttrTailKind,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MayaAddAttrTailKind {
    None,
    Numeric,
    String,
    Mixed,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaConnectAttrCommand {
    pub source_attr: Option<MayaRawShellItem>,
    pub target_attr: Option<MayaRawShellItem>,
    pub next_available: bool,
    pub lock_arg: Option<MayaRawShellItem>,
    pub flags: Vec<MayaNormalizedFlag>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightConnectAttrCommand {
    pub source_attr: Option<MayaRawShellItem>,
    pub target_attr: Option<MayaRawShellItem>,
    pub next_available: bool,
    pub lock_arg: Option<MayaRawShellItem>,
    pub flags: Vec<MayaLightFlag>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaRelationshipCommand {
    pub relationship: Option<MayaRawShellItem>,
    pub members: Vec<MayaRawShellItem>,
    pub flags: Vec<MayaNormalizedFlag>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightRelationshipCommand {
    pub relationship: Option<MayaRawShellItem>,
    pub members: Vec<MayaRawShellItem>,
    pub flags: Vec<MayaLightFlag>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaFileCommand {
    pub path: Option<MayaRawShellItem>,
    pub namespace: Option<MayaRawShellItem>,
    pub reference_node: Option<MayaRawShellItem>,
    pub file_type: Option<MayaRawShellItem>,
    pub options: Option<MayaRawShellItem>,
    pub is_reference: bool,
    pub flags: Vec<MayaNormalizedFlag>,
    pub span: TextRange,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MayaLightFileCommand {
    pub path: Option<MayaRawShellItem>,
    pub namespace: Option<MayaRawShellItem>,
    pub reference_node: Option<MayaRawShellItem>,
    pub file_type: Option<MayaRawShellItem>,
    pub options: Option<MayaRawShellItem>,
    pub is_reference: bool,
    pub flags: Vec<MayaLightFlag>,
    pub opaque_tail: Option<TextRange>,
    pub span: TextRange,
}