in src/DocBlock/DocBlock.hack [33:142]
public function __construct(private string $rawDocBlock) {
$lines = $rawDocBlock
|> Str\trim($$)
|> Str\strip_prefix($$, '/**')
|> Str\strip_suffix($$, '*/')
|> Str\trim($$)
|> Str\split($$, "\n")
|> Vec\map($$, $l ==> Str\trim_left($l));
$content_lines = vec[];
$finished_content = false;
$at_lines = vec[];
foreach ($lines as $line) {
if (Str\starts_with($line, '* ')) {
$line = Str\strip_prefix($line, '* ');
} else {
$line = Str\strip_prefix($line, '*');
}
if (Str\starts_with($line, '@')) {
$finished_content = true;
}
if ($finished_content) {
$at_lines[] = $line;
continue;
} else {
$content_lines[] = $line;
continue;
}
}
$content = Str\trim_left(Str\join($content_lines, "\n"));
// Find first period that is not nested e.g. inside a link's URL.
$first_period = null;
$nesting_level = 0;
for ($i = 0; $i < Str\length($content); ++$i) {
if ($content[$i] === '.' && $nesting_level === 0) {
$first_period = $i;
break;
} else if ($content[$i] === '(' || $content[$i] === '[') {
++$nesting_level;
} else if ($content[$i] === ')' || $content[$i] === ']') {
// Trim at 0 in case the docblock is not correctly parenthesized.
$nesting_level = Math\maxva($nesting_level - 1, 0);
}
}
if ($first_period !== null) {
// Handle '...'
$slice = Str\slice($content, $first_period);
$x = Str\trim_left($slice, '.');
$diff = Str\length($slice) - Str\length($x);
if ($diff > 2) {
$first_period = Str\search($content, '.', $first_period + $diff);
}
}
$first_para = Str\search($content, "\n\n");
if ($first_period === null && $first_para !== null) {
$sep = $first_para;
} else if ($first_period !== null && $first_para === null) {
$sep = $first_period;
} else if ($first_period !== null && $first_para !== null) {
$sep = Math\minva($first_para, $first_period);
} else {
$sep = null;
}
if ($sep === null && $content !== '') {
$this->summary = $content;
} else if ($sep !== null) {
$this->summary = Str\trim(Str\slice($content, 0, $sep));
$description = Str\trim(Str\slice($content, $sep + 1));
if ($description !== '') {
$this->description = $description;
}
}
$current_tag = null;
$tags = vec[];
foreach ($at_lines as $line) {
$line = Str\trim($line);
if (Str\starts_with($line, '@')) {
if ($current_tag !== null) {
$tags[] = $current_tag;
}
$current_tag = $line;
} else {
$current_tag .= "\n".$line;
}
}
if ($current_tag !== null) {
$tags[] = $current_tag;
}
foreach ($tags as $tag) {
$space = Str\search($tag, ' ');
if ($space === null) {
$this->tags[] = tuple($tag, null);
continue;
}
$key = Str\slice($tag, 0, $space);
$value = Str\trim(Str\slice($tag, $space + 1));
$this->tags[] = tuple($key, $value);
}
}