Skip to content

Commit fc88749

Browse files
authored
task build completions datasets for ace autocompleters (#1968)
* feature: first version of flow dsl completer for ace editor * feature: added scalar_function_chain:bool property to dsl.json * fix: broken default values in plauground autocompleter * feature: extend build:docs by dumping methods of api classes * feature: added commands to generate ace editor completers code * refactoring: migrated from ace editor to coddemirror Aceeditor is great but it's lacking a good documentation and examples. On top of that building autocompleter is a nightmare, codemirror is much more developer friendly. * fix: sharing playground code after migration to code mirror * feature: added flow completer to playground * feature: added dsl completer to playground * feature: added dataframe completer to playground - fixed dsl completer by making him to not suggest dsl function on methods * feature: added scalar function chain completer to playground * fix: dsl autocompleter not creating functions with full namespace * fix: tab button now put tabs in editor instead of jumping to another input on website * feature: added playground storage to keep most recent code in browser storage * Fixed autocompletion on fluent interface * feature: allow to lazy load files to wasm filesystem - moved loading flow.phar from playground-editor_controller.js to our new dynamic loading mechanism * feature: added status to code editor that showes from where the code is loaded * feature: added file browser to flow playground * feature: move all playground code to /workspace folder in wasm filesystem this prevents displaying other files required by wasm and creates a clean workspace * feature: added format action to playground format action uses php-cs-fixer under the hood to format the code and update editor * feature: allow users to upload their own local files to playground * refactoring: moved away from hardcoded svg icons in playground editor * feature: move all notification to editor output console * feature: added help to playground editor * feature: added more content to help section * feature: added file preview when user clicks on a file in files browser he will see a readonly preview of that file below the editor * fix: comands generating code completers for playground were missing in website build action * fix: removed timestamp from completers templates to avoid creating empty diffs when nothing changed
1 parent d9b8581 commit fc88749

File tree

84 files changed

+14442
-556
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+14442
-556
lines changed

.php-cs-fixer.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@
2626
__DIR__ . '/src/lib/**/tests',
2727
__DIR__ . '/src/tools/**/src',
2828
__DIR__ . '/src/tools/**/tests',
29-
__DIR__ . '/web/**/src',
30-
__DIR__ . '/web/**/tests',
29+
__DIR__ . '/web/landing/src',
30+
__DIR__ . '/web/landing/tests',
31+
__DIR__ . '/web/landing/bin',
3132
__DIR__ . '/examples',
3233
__DIR__ . '/tools/rector/src',
3334
])

bin/docs.php

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
declare(strict_types=1);
55

6-
use Flow\Documentation\{FunctionCollector, FunctionsExtractor};
6+
use Flow\Documentation\{FunctionCollector, FunctionsExtractor, MethodCollector, MethodsExtractor};
77
use Flow\ETL\Attribute\Module;
8+
use Flow\ETL\DataFrame\GroupedDataFrame;
9+
use Flow\ETL\{DataFrame, Flow};
10+
use Flow\ETL\Function\ScalarFunctionChain;
811
use Symfony\Component\Console\Application;
912
use Symfony\Component\Console\Command\Command;
1013
use Symfony\Component\Console\Input\{InputArgument, InputInterface};
@@ -81,4 +84,44 @@ public function execute(InputInterface $input, OutputInterface $output) : int
8184
}
8285
});
8386

87+
$application->add(new class extends Command {
88+
public function configure() : void
89+
{
90+
$this
91+
->setName('api:dump')
92+
->setDescription('Dump API methods from classes into json file.')
93+
->addArgument('output', InputArgument::REQUIRED, 'Where to dump methods.');
94+
}
95+
96+
public function execute(InputInterface $input, OutputInterface $output) : int
97+
{
98+
$repositoryRootPath = dirname(__DIR__) . '/';
99+
100+
$classes = [
101+
ScalarFunctionChain::class,
102+
Flow::class,
103+
DataFrame::class,
104+
GroupedDataFrame::class,
105+
];
106+
107+
$normalizedMethods = [];
108+
109+
foreach ($classes as $className) {
110+
$extractor = new MethodsExtractor(
111+
$repositoryRootPath,
112+
$className,
113+
new MethodCollector()
114+
);
115+
116+
foreach ($extractor->extract() as $method) {
117+
$normalizedMethods[] = $method->normalize();
118+
}
119+
}
120+
121+
\file_put_contents(__DIR__ . '/../' . \ltrim((string) $input->getArgument('output'), '/'), \json_encode($normalizedMethods));
122+
123+
return Command::SUCCESS;
124+
}
125+
});
126+
84127
$application->run();

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,15 +432,16 @@
432432
"build:phar": [
433433
"composer update --working-dir=./src/cli",
434434
"tools/box/vendor/bin/box compile --config ./src/cli/box.json",
435-
"cp ./build/flow.phar ./web/landing/assets/wasm/flow.phar"
435+
"cp ./build/flow.phar ./web/landing/assets/wasm/tools/flow.phar"
436436
],
437437
"build:wasm": [
438438
"Composer\\Config::disableProcessTimeout",
439439
"cd wasm && ./build.sh",
440440
"@build:phar"
441441
],
442442
"build:docs": [
443-
"bin/docs.php dsl:dump web/landing/resources/dsl.json"
443+
"bin/docs.php dsl:dump web/landing/resources/dsl.json",
444+
"bin/docs.php api:dump web/landing/resources/api.json"
444445
],
445446
"build:docs:api": [
446447
"./tools/phpdocumentor/vendor/bin/phpdoc --config=./phpdoc/core.xml",

rector.src.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
__DIR__ . '/src/adapter/*/src',
1818
__DIR__ . '/src/bridge/*/src',
1919
__DIR__ . '/src/tools/*/src',
20+
__DIR__ . '/web/landing/src',
2021
])
2122
->withSkip([
2223
RemoveExtraParametersRector::class,

rector.tests.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
__DIR__ . '/src/adapter/*/*/tests',
8787
__DIR__ . '/src/bridge/*/*/tests',
8888
__DIR__ . '/src/tools/*/*/tests',
89+
__DIR__ . '/web/landing/tests',
8990
])
9091
->withSets([
9192
LevelSetList::UP_TO_PHP_82,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Flow\Documentation;
6+
7+
final class MethodCollector
8+
{
9+
/**
10+
* @var array<string>
11+
*/
12+
public array $methods = [];
13+
14+
/**
15+
* @param class-string $className
16+
*/
17+
public function collect(string $className) : void
18+
{
19+
$reflectionClass = new \ReflectionClass($className);
20+
$methods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);
21+
22+
foreach ($methods as $method) {
23+
if ($method->getDeclaringClass()->getName() !== $className) {
24+
continue;
25+
}
26+
27+
// Skip magic methods __construct and __destruct
28+
if ($method->getName() === '__construct' || $method->getName() === '__destruct') {
29+
continue;
30+
}
31+
32+
$this->methods[] = $method->getName();
33+
}
34+
}
35+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Flow\Documentation;
6+
7+
use Flow\Documentation\Models\MethodModel;
8+
9+
final readonly class MethodsExtractor
10+
{
11+
/**
12+
* @param class-string $className
13+
*/
14+
public function __construct(
15+
private string $repositoryRootPath,
16+
private string $className,
17+
private MethodCollector $methodCollector,
18+
) {
19+
}
20+
21+
/**
22+
* @return \Generator<MethodModel>
23+
*/
24+
public function extract() : \Generator
25+
{
26+
$this->methodCollector->collect($this->className);
27+
28+
$reflectionClass = new \ReflectionClass($this->className);
29+
30+
foreach ($this->methodCollector->methods as $methodName) {
31+
$reflectionMethod = $reflectionClass->getMethod($methodName);
32+
$repositoryPath = \ltrim(\str_replace($this->repositoryRootPath, '', (string) $reflectionMethod->getFileName()), '/');
33+
34+
yield MethodModel::fromReflection(
35+
$repositoryPath,
36+
$reflectionMethod
37+
);
38+
}
39+
}
40+
}

src/tools/documentation/src/Flow/Documentation/Models/AttributesModel.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static function fromArray(array $data) : self
2828
);
2929
}
3030

31-
public static function fromReflection(\ReflectionFunction $reflection) : self
31+
public static function fromReflection(\ReflectionFunction|\ReflectionMethod $reflection) : self
3232
{
3333
return new self(
3434
array_map(

src/tools/documentation/src/Flow/Documentation/Models/FunctionModel.php

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
namespace Flow\Documentation\Models;
66

7-
use function Flow\Types\DSL\{type_array, type_integer, type_optional, type_string, type_structure};
7+
use function Flow\Types\DSL\{type_array, type_boolean, type_integer, type_optional, type_string, type_structure};
88
use Cocur\Slugify\Slugify;
9+
use Flow\ETL\Function\ScalarFunctionChain;
910

1011
final readonly class FunctionModel
1112
{
@@ -18,6 +19,7 @@ public function __construct(
1819
public ParametersModel $parameters,
1920
public TypesModel $returnType,
2021
public AttributesModel $attributes,
22+
public bool $scalarFunctionChain,
2123
public ?string $docComment = null,
2224
) {
2325

@@ -37,6 +39,7 @@ public static function fromArray(array $data) : self
3739
'parameters' => type_array(),
3840
'return_type' => type_array(),
3941
'attributes' => type_array(),
42+
'scalar_function_chain' => type_boolean(),
4043
'doc_comment' => type_optional(type_string()),
4144
])->assert($data);
4245

@@ -56,6 +59,7 @@ public static function fromArray(array $data) : self
5659
ParametersModel::fromArray($parameters),
5760
TypesModel::fromArray($returnType),
5861
AttributesModel::fromArray($attributes),
62+
$data['scalar_function_chain'],
5963
$data['doc_comment']
6064
);
6165
}
@@ -77,6 +81,7 @@ public static function fromReflection(string $relativePath, \ReflectionFunction
7781
ParametersModel::fromFunctionReflection($reflectionFunction),
7882
TypesModel::fromReflection($returnTypeReflection),
7983
AttributesModel::fromReflection($reflectionFunction),
84+
self::isScalarFunctionChain($returnTypeReflection),
8085
$reflectionFunction->getDocComment() ? \base64_encode($reflectionFunction->getDocComment()) : null,
8186
);
8287
}
@@ -95,7 +100,31 @@ public function normalize() : array
95100
'parameters' => $this->parameters->normalize(),
96101
'return_type' => $this->returnType->normalize(),
97102
'attributes' => $this->attributes->normalize(),
103+
'scalar_function_chain' => $this->scalarFunctionChain,
98104
'doc_comment' => $this->docComment,
99105
];
100106
}
107+
108+
private static function isScalarFunctionChain(\ReflectionType $reflectionType) : bool
109+
{
110+
if ($reflectionType instanceof \ReflectionNamedType) {
111+
$typeName = $reflectionType->getName();
112+
113+
if (!\class_exists($typeName)) {
114+
return false;
115+
}
116+
117+
return \is_a($typeName, ScalarFunctionChain::class, true);
118+
}
119+
120+
if ($reflectionType instanceof \ReflectionUnionType || $reflectionType instanceof \ReflectionIntersectionType) {
121+
foreach ($reflectionType->getTypes() as $type) {
122+
if (self::isScalarFunctionChain($type)) {
123+
return true;
124+
}
125+
}
126+
}
127+
128+
return false;
129+
}
101130
}

0 commit comments

Comments
 (0)