<commit_before>my role Subcommand {
    has Str $.command-name is rw;
}

my class SubcommanderException is Exception {
    has Str $.message;

    method new(Str $message) {
        self.bless(:$message);
    }
}

my class NoMoreValues is Exception {
    method message { 'No more values' }
}

my class Option {
    has $.content;

    method Str { $.content }
}

my class Target {
    has $.content;

    method Str { $.content }
}

my class TypeResolver {
    has %!named;
    has @!positional;

    submethod BUILD(:&command) {
        for &command.signature.params -> $param {
            next if $param.invocant;
            next if $param.slurpy;

            if $param.named {
                for $param.named_names -> $name {
                    %!named{$name} = $param.type;
                }
            } else {
                @!positional.push: $param.type;
            }
        }
    }

    method is-array(Str $name) returns Bool {
        %!named{$name} ~~ Positional # XXX is ~~ the right test?
    }

    multi method typeof(Int $pos) {
        @!positional[$pos]
    }

    multi method typeof(Str $name) {
        %!named{$name}
    }
}

my class OptionCanonializer {
    has %!canonical-names;

    submethod BUILD(:&command) {
        %!canonical-names = gather {
            for &command.signature.params -> $param {
                next unless $param.named;
                next if $param.slurpy;

                my $first-name = $param.named_names[0];
                for $param.named_names -> $name {
                    take $name => $first-name;
                }
            }
        };
    }

    method canonicalize(Str $name) returns Str {
        %!canonical-names{$name} // $name<commit_msg>Strip no/no- from boolean flags<commit_after>my role Subcommand {
    has Str $.command-name is rw;
}

my class SubcommanderException is Exception {
    has Str $.message;

    method new(Str $message) {
        self.bless(:$message);
    }
}

my class NoMoreValues is Exception {
    method message { 'No more values' }
}

my class Option {
    has $.content;

    method Str { $.content }
}

my class Target {
    has $.content;

    method Str { $.content }
}

my class TypeResolver {
    has %!named;
    has @!positional;

    submethod BUILD(:&command) {
        for &command.signature.params -> $param {
            next if $param.invocant;
            next if $param.slurpy;

            if $param.named {
                for $param.named_names -> $name {
                    %!named{$name} = $param.type;
                }
            } else {
                @!positional.push: $param.type;
            }
        }
    }

    method is-array(Str $name) returns Bool {
        %!named{$name} ~~ Positional # XXX is ~~ the right test?
    }

    multi method typeof(Int $pos) {
        @!positional[$pos]
    }

    multi method typeof(Str $name is copy) {
        unless %!named{$name}:exists {
            $name .= subst(/^ no '-'? /, '')
        }
        %!named{$name}
    }
}

my class OptionCanonializer {
    has %!canonical-names;

    submethod BUILD(:&command) {
        %!canonical-names = gather {
            for &command.signature.params -> $param {
                next unless $param.named;
                next if $param.slurpy;

                my $first-name = $param.named_names[0];
                for $param.named_names -> $name {
                    take $name => $first-name;
                }
            }
        };
    }

    method canonicalize(Str $name is copy) returns Str {
        unless %!canonical-names{$name}:exists {
            $name .= subst(/^ no '-'? /, '')
        }
        %!canonical-names{$name} // $name
{'fraction_non_alphanumeric': 0.12662689804772234, 'fraction_numerical': 0.0005422993492407809, 'mean_word_length': 1.6200284090909092, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1037490', 'n_tokens_mistral': 1133, 'n_tokens_neox': 1086, 'n_words': 277}