refactor: Cleanup git state - commit all staged changes

Major refactoring cleanup:
- Add new controller architecture (class-controller-*.php)
- Add new settings-v2 UI (views/settings-v2/)
- Add new CSS architecture (agentic-sidebar.css, tokens)
- Add esbuild build pipeline (scripts/build.js, package.json)
- Add composer dependencies (vendor/)
- Add frontend src directory (assets/js/src/index.jsx)
- Add documentation files
- Remove old/obsolete files (class-settings.php, old CSS)

This commits all pending changes from previous refactoring efforts.
This commit is contained in:
Dwindi Ramadhana
2026-06-17 05:27:58 +07:00
parent d3f142222c
commit 690991c526
7963 changed files with 941566 additions and 67372 deletions

View File

@@ -0,0 +1,130 @@
<?php declare(strict_types=1);
/*
* This file is part of the Parsica library.
*
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Tests\Parsica\Parsica\Examples;
use PHPUnit\Framework\TestCase;
use Parsica\Parsica\Parser;
use Parsica\Parsica\PHPUnit\ParserAssertions;
use function Parsica\Parsica\{between, char, choice, keepFirst, recursive, skipHSpace, string};
use function Parsica\Parsica\Expression\{binaryOperator, expression, leftAssoc, prefix, unaryOperator};
final class BooleanExpressionsTest extends TestCase
{
use ParserAssertions;
/** @test */
public function booleanExpressions()
{
$token = fn(Parser $parser) : Parser => keepFirst($parser, skipHSpace());
$parens = fn (Parser $parser): Parser => $token(between($token(char('(')), $token(char(')')), $parser));
$term = fn(): Parser => $token(choice(
string("TRUE")->map(fn($v) => new True_),
string("FALSE")->map(fn($v) => new False_),
));
$NOT = unaryOperator($token(string("NOT")), fn($v) => new Not_($v));
$AND = binaryOperator($token(string("AND")), fn($l, $r) => new And_($l, $r));
$OR = binaryOperator($token(string("OR")), fn($l, $r) => new Or_($l, $r));
$expr = recursive();
$expr->recurse(expression(
$parens($expr)->or($term()),
[
prefix($NOT),
leftAssoc($AND),
leftAssoc($OR),
]
));
$parser = $expr->thenEof();
$input = "TRUE AND NOT (FALSE AND FALSE)";
$expected =
new And_(
new True_(),
new Not_(
new And_(
new False_(),
new False_()
)
)
);
$this->assertParses($input, $parser, $expected);
$parser = $expr->thenEof();
$input = "TRUE AND NOT (FALSE OR TRUE AND FALSE)";
$expected =
new And_(
new True_,
new Not_(
new Or_(
new False_,
new And_(
new True_,
new False_
)
)
)
);
$this->assertParses($input, $parser, $expected);
// Now swapping precedence of AND and OR
$expr = recursive();
$expr->recurse(expression(
$parens($expr)->or($term()),
[
prefix($NOT),
leftAssoc($OR),
leftAssoc($AND),
]
));
$parser = $expr->thenEof();
$input = "TRUE AND NOT (FALSE OR TRUE AND FALSE)";
$expected =
new And_(
new True_,
new Not_(
new And_(
new Or_(
new False_,
new True_
),
new False_
)
)
);
$this->assertParses($input, $parser, $expected);
}
}
interface Boolean_ {}
class True_ implements Boolean_ {}
class False_ implements Boolean_ {}
class Not_ implements Boolean_ {
private Boolean_ $boolean;
function __construct(Boolean_ $boolean){$this->boolean = $boolean;}
}
class And_ implements Boolean_ {
private Boolean_ $l, $r;
function __construct(Boolean_ $l, Boolean_ $r){
$this->l = $l;
$this->r = $r;
}
}
class Or_ implements Boolean_ {
private Boolean_ $l, $r;
function __construct(Boolean_ $l, Boolean_ $r){
$this->l = $l;
$this->r = $r;
}
}

View File

@@ -0,0 +1,63 @@
<?php declare(strict_types=1);
/*
* This file is part of the Parsica library.
*
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Tests\Parsica\Parsica\Examples;
use PHPUnit\Framework\TestCase;
use Parsica\Parsica\Parser;
use function Parsica\Parsica\{atLeastOne, between, char, digitChar, keepFirst, recursive, skipHSpace, string};
use function Parsica\Parsica\Expression\{binaryOperator,
expression,
leftAssoc,
postfix,
prefix,
unaryOperator};
/**
* Parse expressions and calculate the result
*/
final class CalculatorTest extends TestCase
{
/** @test */
public function calculator()
{
$token = fn(Parser $parser) => keepFirst($parser, skipHSpace());
$parens = fn (Parser $parser): Parser => $token(between($token(char('(')), $token(char(')')), $parser));
$term = fn(): Parser => $token(atLeastOne(digitChar()));
$expr = recursive();
$expr->recurse(expression(
$parens($expr)->or($term()),
[
prefix(
unaryOperator(char('-'), fn($v) => -$v),
unaryOperator(char('+'), fn($v) => $v),
),
postfix(
unaryOperator($token(string('--')), fn($v) => $v - 1),
unaryOperator($token(string('++')), fn($v) => $v + 1),
),
leftAssoc(
binaryOperator($token(char('*')), fn($l, $r) => $l * $r),
binaryOperator($token(char('/')), fn($l, $r) => $l / $r),
),
leftAssoc(
binaryOperator($token(char('+')), fn($l, $r) => $l + $r),
binaryOperator($token(char('-')), fn($l, $r) => $l - $r),
),
]
));
$parser = $expr->thenEof();
$result = $parser->tryString("(3 - 2) + -1 - 3 * (1 + 1) / 6");
$this->assertEquals(-1, (string)$result->output());
}
}

View File

@@ -0,0 +1,131 @@
<?php declare(strict_types=1);
/*
* This file is part of the Parsica library.
*
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Tests\Parsica\Parsica\Examples;
use PHPUnit\Framework\TestCase;
use Parsica\Parsica\Parser;
use Parsica\Parsica\PHPUnit\ParserAssertions;
use function Parsica\Parsica\{alphaChar, between, char, collect, digitChar, skipHSpace1, space, string};
final class ExcelTest extends TestCase
{
use ParserAssertions;
/** @test */
public function spaceOrOperatorDependingOnContext()
{
// https://twitter.com/Mark_Baker/status/1309919606887374849?s=20
// and https://twitter.com/Mark_Baker/status/1309960902482026498?s=20
// `=SUM(B7:D7 C6:C8)` where space is the intersection operator for the
// intersection between the two ranges B7:D7 and C6:C8 (ie. C7),
// and `=A1 & B1` where the space is simply whitespace and should be ignored
$parser = $this->excelParser();
$input = "=SUM(B7:D7 C6:C8)";
$expected = new Sum(
new Intersection(
new Range(new Cell("B", "7"), new Cell("D", "7")),
new Range(new Cell("C", "6"), new Cell("C", "8")),
)
);
$this->assertParses($input, $parser, $expected);
$input = "=A1 & B1";
$expected = new Ampersand(
new Cell("A", "1"),
new Cell("B", "1"),
);
$this->assertParses($input, $parser, $expected);
}
private function excelParser(): Parser
{
$parens = fn(Parser $p): Parser => between(char('('), char(')'), $p);
$cell = collect(alphaChar(), digitChar())
->map(fn($o) => new Cell($o[0], $o[1]));
$range = collect($cell, char(':'), $cell)
->map(fn($o) => new Range($o[0], $o[2]));
$intersection = collect($range, space(), $range)
->map(fn($o) => new Intersection($o[0], $o[2]));
$sum = (string('=SUM')->followedBy($parens($intersection)))
->map(fn($o) => new Sum($o));
// consumes space before and after Parser $p
$token = fn(Parser $p): Parser => between(skipHSpace1(), skipHSpace1(), $p);
$ampersand = char('=')->followedBy(collect(
$cell,
$token(char('&')),
$cell
))->map(fn($o) => new Ampersand($o[0], $o[2]));
return $sum->or($ampersand);
}
}
class Cell
{
private $col;
private $row;
function __construct($col, $row)
{
$this->col = $col;
$this->row = $row;
}
}
class Range
{
private Cell $from;
private Cell $to;
function __construct(Cell $from, Cell $to)
{
$this->from = $from;
$this->to = $to;
}
}
class Intersection
{
private Range $l;
private Range $r;
function __construct(Range $l, Range $r)
{
$this->l = $l;
$this->r = $r;
}
}
class Sum
{
private Intersection $intersection;
function __construct(Intersection $intersection)
{
$this->intersection = $intersection;
}
}
class Ampersand
{
private Cell $l;
private Cell $r;
function __construct(Cell $l, Cell $r)
{
$this->l = $l;
$this->r = $r;
}
}

View File

@@ -0,0 +1,47 @@
<?php declare(strict_types=1);
/**
* This file is part of the Parsica library.
*
* Copyright (c) 2020 Mathias Verraes <mathias@verraes.net>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Tests\Parsica\Parsica\Examples;
use Parsica\Parsica\PHPUnit\ParserAssertions;
use PHPUnit\Framework\TestCase;
use function Parsica\Parsica\any;
use function Parsica\Parsica\collect;
use function Parsica\Parsica\digitChar;
use function Parsica\Parsica\repeat;
use function Parsica\Parsica\skipSpace;
use function Parsica\Parsica\string;
final class SimpleDateTest extends TestCase
{
use ParserAssertions;
/** @test */
public function simple_date()
{
$jan = (string("January")->or(string("Jan")))->map(fn($v) => 1);
$feb = (string("February")->or(string("Feb")))->map(fn($v) => 2);
$mar = (string("March")->or(string("Mar")))->map(fn($v) => 3);
// ... you get the gist
$month = any($jan, $feb, $mar);
$day = repeat(2, digitChar())->map('intval');
$p1 = collect(
$month->thenIgnore(skipSpace()),
$day
);
$this->assertParses("January 28", $p1, [1, 28]);
$this->assertParses("Jan 28", $p1, [1, 28]);
$this->assertParses("February 28", $p1, [2, 28]);
$this->assertParses("Feb 28", $p1, [2, 28]);
}
}