src/APIIndex.php (170 lines of code) (raw):
<?hh // strict
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
namespace HHVM\UserDocumentation;
use namespace Facebook\TypeAssert;
use namespace HH\Lib\Vec;
final class APIIndex {
private ProductAPIIndexShape $index;
private function __construct(private APIProduct $product) {
$idx = self::getRawIndex();
switch ($product) {
case APIProduct::HACK:
$this->index = $idx[APIProduct::HACK];
break;
case APIProduct::HSL:
$this->index = $idx[APIProduct::HSL];
break;
case APIProduct::HSL_EXPERIMENTAL:
$this->index = $idx[APIProduct::HSL_EXPERIMENTAL];
break;
}
}
<<__Memoize>>
public static function get(APIProduct $product): APIIndex {
return new self($product);
}
public function getIndex(): ProductAPIIndexShape {
return $this->index;
}
public static function searchAllProducts(string $term): vec<SearchResult> {
return Vec\concat(
self::get(APIProduct::HACK)->search($term),
self::get(APIProduct::HSL)->search($term),
);
}
<<__Memoize>>
private static function getRawIndex(): APIIndexShape {
return apc_fetch_or_set_class_data(
self::class,
() ==> JSON\decode_as_shape(
APIIndexShape::class,
\file_get_contents(BuildPaths::APIDOCS_INDEX_JSON),
),
);
}
public function getIndexForType(
APIDefinitionType $type,
): dict<string, APIIndexEntry> {
$index = Shapes::toArray($this->index);
invariant(
\array_key_exists($type, $index),
'invalid type: %s',
(string)$type,
);
return $index[$type];
}
public function getFunctionIndex(): dict<string, APIFunctionIndexEntry> {
return $this->index['function'];
}
public function getClassIndex(
APIDefinitionType $type,
): dict<string, APIClassIndexEntry> {
switch ($type) {
case APIDefinitionType::FUNCTION_DEF:
invariant_violation('functions are not classes');
case APIDefinitionType::CLASS_DEF:
return $this->index['class'];
case APIDefinitionType::INTERFACE_DEF:
return $this->index['interface'];
case APIDefinitionType::TRAIT_DEF:
return $this->index['trait'];
}
}
public function search(string $term): vec<SearchResult> {
return APIDefinitionType::getValues()
|> Vec\map($$, $type ==> $this->searchEntries($term, $type))
|> Vec\flatten($$);
}
private function getMethods(APIIndexEntry $entry): ?vec<APIMethodIndexEntry> {
$methods = $entry['methods'] ?? null;
if ($methods !== null) {
return Vec\map(
$methods,
$method ==> TypeAssert\matches_type_structure(
type_alias_structure(APIMethodIndexEntry::class),
$method,
),
);
}
return null;
}
private function searchEntries(
string $term,
APIDefinitionType $type,
): vec<SearchResult> {
$results = vec[];
$entries = $this->getIndexForType($type);
foreach ($entries as $_ => $entry) {
$name = $entry['name'];
$score = SearchTermMatcher::matchTerm($name, $term);
if ($score !== null) {
$results[] = new APISearchResult(
$this->product,
$type,
$name,
$entry['urlPath'],
$score,
);
}
$methods = $this->getMethods($entry);
if ($methods === null) {
continue;
}
foreach ($methods as $method) {
$name = $entry['name'].'::'.$method['name'];
$score = SearchTermMatcher::matchTerm($name, $term);
if ($score !== null) {
$results[] = new APISearchResult(
$this->product,
APIDefinitionType::FUNCTION_DEF,
$name,
$method['urlPath'],
$score,
);
}
}
}
return $results;
}
public function getDataForFunction(string $name): APIFunctionIndexEntry {
$index = $this->index;
invariant(
\array_key_exists($name, $index['function']),
'function %s does not exist',
$name,
);
return $index['function'][$name];
}
public function getDataForClass(
APIDefinitionType $class_type,
string $class_name,
): APIClassIndexEntry {
$index = $this->getClassIndex($class_type);
invariant(
\array_key_exists($class_name, $index),
'class %s does not exist',
$class_name,
);
return $index[$class_name];
}
public function getDataForMethod(
APIDefinitionType $class_type,
string $class_name,
string $method_name,
): APIMethodIndexEntry {
$index = $this->getClassIndex($class_type);
invariant(
\array_key_exists($class_name, $index),
'class %s does not exist',
$class_name,
);
$class = $index[$class_name];
$methods = $class['methods'];
invariant(
\array_key_exists($method_name, $methods),
'Method %s::%s does not exist',
$class_name,
$method_name,
);
return $methods[$method_name];
}
}