• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

moonbitlang / x / 867

18 Jun 2026 06:38AM UTC coverage: 88.523% (+1.7%) from 86.827%
867

push

github

myfreess
path: document Node-compatible dispatch

2553 of 2884 relevant lines covered (88.52%)

338.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.91
/path/posix/unix_path.mbt
1
// Copyright 2025 International Digital Economy Academy
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
///|
16
priv enum UnixPrefix {
17
  /// Syntax: `/` or `/{3,}`
18
  ///
19
  /// A pathname consisting of a single <slash> shall resolve to the root directory of the process.
20
  Root
21
  SlashSlash
22
  None
23
} derive(ToJson, Hash, Eq)
24

25
///|
26
/// [Posix 4.13 Pathname Resolution](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13)
27
/// 
28
/// 
29
priv struct UnixPath {
30
  prefix : UnixPrefix
31
  trailing_separator : Bool
32
  components : Array[StringView]
33
} derive(ToJson, Hash, Eq)
34

35
///|
36
fn is_unix_sep_at(path : StringView, index : Int) -> Bool {
37
  path.get_char(index) == Some('/')
2,937✔
38
}
39

40
///|
41
impl Show for UnixPath with fn output(self : UnixPath, logger : &Logger) -> Unit {
42
  let { prefix, trailing_separator, components } = self
181✔
43
  match prefix {
181✔
44
    Root => logger.write_char('/')
95✔
45
    SlashSlash => logger.write_char('/')
×
46
    None => ()
86✔
47
  }
48
  match components {
181✔
49
    [] =>
50
      if prefix is None {
35✔
51
        if trailing_separator {
11✔
52
          logger.write_string("./")
4✔
53
        } else {
54
          logger.write_char('.')
7✔
55
        }
56
      }
57
    [x, .. xs] => {
146✔
58
      logger.write_view(x)
146✔
59
      for x in xs {
60
        logger.write_char('/')
144✔
61
        logger.write_view(x)
144✔
62
      }
63
      if trailing_separator {
64
        logger.write_char('/')
19✔
65
      }
66
    }
67
  }
68
}
69

70
///|
71
fn push_unix_component(
72
  components : Array[StringView],
73
  component : StringView,
74
  allow_above_root~ : Bool,
75
) -> Unit {
76
  match component {
489✔
77
    "." => ()
32✔
78
    ".." =>
79
      match components.pop() {
60✔
80
        Some("..") => {
×
81
          components.push("..")
×
82
          if allow_above_root {
83
            components.push("..")
×
84
          }
85
        }
86
        None => if allow_above_root { components.push("..") }
8✔
87
        Some(_) => ()
47✔
88
      }
89
    _ => components.push(component)
397✔
90
  }
91
}
92

93
///|
94
fn skip_unix_separators(path : StringView, start : Int) -> Int {
95
  let mut index = start
462✔
96
  while index < path.length() && is_unix_sep_at(path, index) {
946✔
97
    index += 1
525✔
98
  }
99
  index
100
}
101

102
///|
103
fn parse_unix_components(
104
  path : StringView,
105
  start : Int,
106
  allow_above_root~ : Bool,
107
) -> Array[StringView] {
108
  let components : Array[StringView] = []
208✔
109
  let mut component_start = start
110
  let mut index = start
111
  while index <= path.length() {
1,789✔
112
    if index == path.length() || is_unix_sep_at(path, index) {
1,581✔
113
      if component_start < index {
533✔
114
        push_unix_component(
489✔
115
          components,
116
          path[component_start:index],
117
          allow_above_root~,
118
        )
119
      }
120
      if index == path.length() {
533✔
121
        break
208✔
122
      }
123
      index = skip_unix_separators(path, index)
325✔
124
      component_start = index
125
    } else {
126
      index += 1
1,256✔
127
    }
128
  }
129
  components
130
}
131

132
///|
133
fn UnixPath::parse(path : StringView) -> UnixPath {
134
  let prefix = if !path.is_empty() && is_unix_sep_at(path, 0) {
205✔
135
    Root
137✔
136
  } else {
137
    None
71✔
138
  }
139
  let start = if prefix is Root { skip_unix_separators(path, 0) } else { 0 }
71✔
140
  let trailing_separator = path.length() > 0 &&
208✔
141
    is_unix_sep_at(path, path.length() - 1)
205✔
142
  let components = parse_unix_components(
208✔
143
    path,
144
    start,
145
    allow_above_root=prefix is None,
146
  )
147
  { prefix, trailing_separator, components }
148
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc