定制 abstract/core 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

abstract/core

Composer 安装命令:

composer require abstract/core

包简介

Spec-first, language-agnostic tree processor with a PHP v0 implementation.

README 文档

README

Abstract is a spec-first, language-agnostic tree processor. It turns structured source formats into a canonical Abstract Tree, resolves safe runtime nodes, maps that tree into a target model, and emits output such as HTML, JSX, JSON, schemas, workflows, or future custom targets.

This repository is the PHP v0 implementation. The concepts, fixtures, and docs are intentionally portable so a future JavaScript/TypeScript implementation can follow the same behavior.

Status

Abstract Core v0 currently supports:

  • JSON tag-key syntax
  • canonical element, runtime, value, and fragment nodes
  • primitive type inference
  • explicit typed nodes such as :string, :int, :float, :bool, :null, :array, and :object
  • @ props and # children
  • shorthand object and array children
  • :props and :attributes parent prop modifiers
  • data-based :expr, :if, :else, and :each
  • inline :import and :include
  • DOMDocument-backed HTML and XML markup parsing
  • YAML, TOML, and Pkl parsing through the shared tag-key normalizer
  • compact, tagged, and canonical JSON tree export
  • strict and loose runtime modes
  • HTML, XML, YAML, TOML, Pkl, and JSX-like output pipelines
  • target-aware custom render targets and mapper overrides
  • shared JSON fixtures and PHPUnit coverage
  • benchmark scripts for JSON core flows and large HTML roundtrips

Unsafe code execution is not enabled. :php, :js, :ts, and :code are recognized as payload directives, but the default strict runtime rejects them instead of executing or rendering them.

Installation

composer install

Quick Example

<?php

require 'vendor/autoload.php';

use Abstract\AbstractCore;

$core = new AbstractCore();

$tree = $core->parseJson('{
  "div": {
    "@": {
      "class": "card"
    },
    "#": [
      { "h1": "Title" },
      { "p": "Body" }
    ]
  }
}');

echo $core->renderHtml($tree);
// <div class="card"><h1>Title</h1><p>Body</p></div>

JSON Tag-Key Syntax

The user syntax is tag-key based:

{
  "div": "hello"
}

This normalizes to an element named div with one typed string child.

Canonical props and children:

{
  "div": {
    "@": {
      "class": "card",
      "id": "main"
    },
    "#": [
      {
        "span": "Hello"
      }
    ]
  }
}

Shorthand child objects are supported:

{
  "div": {
    "h1": "Title",
    "p": "Body"
  }
}

Repeated JSON object keys are impossible, so repeated elements must use arrays:

{
  "ul": [
    { "li": "One" },
    { "li": "Two" }
  ]
}

Runtime Nodes

Keys beginning with : are runtime nodes. They are used during processing and are never rendered as literal output tags.

{
  "div": [
    { ":attributes": { "class": "card" } },
    { "span": "Hello" }
  ]
}

This renders as:

<div class="card"><span>Hello</span></div>

Runtime logic is data-based:

{
  ":if": {
    "@": {
      "test": {
        ":expr": { "var": "user.isLoggedIn" }
      }
    },
    "#": [
      { "Dashboard": [] }
    ],
    ":else": [
      { "Login": [] }
    ]
  }
}

Imports

Imports resolve relative to the current source file and are cached by path, mtime, and content hash.

{
  ":import": {
    "@": {
      "src": "./components/Card.abstract.json",
      "props": {
        "title": "Welcome"
      }
    },
    "#": [
      { "p": "This becomes slot content." }
    ]
  }
}

For v0, slot children are appended to the imported root element or fragment. A richer component/slot system can be added later.

HTML Markup Parsing

HTML can be parsed through the same canonical tree model:

use Abstract\AbstractCore;
use Abstract\Emitter\JsonEmitter;
use Abstract\Parser\Markup\MarkupParseOptions;

$core = new AbstractCore();
$tree = $core->parseHtmlFile('benchmarks/big-html.html', new MarkupParseOptions(includeMeta: false));

$compactJson = $core->treeJson($tree, pretty: false, mode: JsonEmitter::MODE_COMPACT);
$html = $core->renderHtml($core->parseJson($compactJson));

The parser uses native DOMDocument/libxml for v0 performance. Correctness is structural: output is not beautified and is not expected to be byte-identical to the source, but parsed nodes, attributes, text, comments, raw script/style content, and doctype data are preserved through the benchmark comparator.

JSON export modes:

  • canonical: full internal kind/name/props/children tree
  • compact: storage-oriented tag-key JSON with fewer model strings
  • tagged: explicit Abstract tags for API/debug use

Text-only markup is treated as content, not as an implicit DOM paragraph:

$tree = $core->parseHtml('Hello Test');

echo $core->treeJson($tree, pretty: false, mode: JsonEmitter::MODE_COMPACT);
// "Hello Test"

echo $core->renderHtml($tree);
// Hello Test

XML, YAML, TOML, And Pkl

All data/config formats decode into native values and then use the same tag-key normalizer as JSON.

$tree = $core->parseYamlFile('page.abstract.yaml');

echo $core->renderHtml($tree);
echo $core->renderYaml($tree);

Available parser methods:

  • parseXml, parseXmlFile
  • parseYaml, parseYamlFile
  • parseToml, parseTomlFile
  • parsePkl, parsePklFile

Available render methods:

  • renderXml
  • renderYaml
  • renderToml
  • renderPkl

YAML supports scalar, list, and map roots. TOML and Pkl rendering require object/map roots because their module/document syntax is property-oriented. Pkl parsing uses the local pkl CLI with eval --format=json --no-project --root-dir; it is an explicit parser path for trusted local config modules, not implicit code execution.

Custom Render Targets

AbstractCore is a facade over parsers, runtime resolution, render targets, and tree serializers. renderHtml(), renderJsx(), and renderXml() use registered render targets internally, and render($target, ...) can call a target by name.

Custom mapping is target-aware. A JSX override does not affect HTML, and an HTML override does not affect JSX.

Custom JSX mapping:

use Abstract\AbstractCore;
use Abstract\Emitter\JsxEmitter;
use Abstract\Mapper\ReactComponent;
use Abstract\Mapper\ReactMapper;
use Abstract\Render\RenderTarget;

$core = AbstractCore::default()
    ->withRenderTarget('jsx', RenderTarget::make(
        ReactMapper::make()
            ->component('input', ReactComponent::imported(
                source: '@headlessui/react',
                export: 'Input',
                as: 'HeadlessInput',
            )),
        new JsxEmitter(),
    ));

echo $core->renderJsx($tree);

Output:

import { Input as HeadlessInput } from "@headlessui/react";

<HeadlessInput name="email" />

Custom HTML mapping:

use Abstract\AbstractCore;
use Abstract\Emitter\HtmlEmitter;
use Abstract\Mapper\HtmlElementMapping;
use Abstract\Mapper\HtmlMapper;
use Abstract\Render\RenderTarget;

$core = AbstractCore::default()
    ->withRenderTarget('html', RenderTarget::make(
        HtmlMapper::make()
            ->element('input', HtmlElementMapping::tag('x-input')),
        new HtmlEmitter(),
    ));

echo $core->renderHtml($tree);

Output:

<x-input name="email"></x-input>

Config-driven customization is also available for simple JSX components and HTML tag replacement:

$core = AbstractCore::fromConfig([
    'targets' => [
        'jsx' => [
            'components' => [
                'input' => [
                    'source' => '@headlessui/react',
                    'export' => 'Input',
                    'as' => 'HeadlessInput',
                ],
            ],
        ],
        'html' => [
            'elements' => [
                'input' => ['tag' => 'x-input'],
            ],
        ],
    ],
]);

YAML, TOML, Pkl, and treeJson() currently serialize resolved Abstract Tree data directly. They remain configurable through their render methods and may gain dedicated mappers later.

Tests

./vendor/bin/phpunit --configuration phpunit.xml

Current verified result:

OK (53 tests, 87 assertions)

Benchmarks

php benchmarks/core-benchmark.php
php benchmarks/markup-benchmark.php

Benchmark results are recorded in PERFORMANCE.md.

Examples

Runnable examples live in examples/. They include JSON-to-HTML, React/JSX mapping, runtime logic, imports, text-only markup, XML/YAML/TOML/Pkl scenarios, custom render targets, a small HTML roundtrip, and a large examples/big-html.html roundtrip that writes compact JSON and HTML output under examples/output/.

Documentation

abstract/core 适用场景与选型建议

abstract/core 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 15 次下载、GitHub Stars 达 0, 最近一次更新时间为 2023 年 05 月 11 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 abstract/core 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 abstract/core 我们能提供哪些服务?
定制开发 / 二次开发

基于 abstract/core 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 15
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 11
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 2
  • 开发语言: PHP

其他信息

  • 授权协议: proprietary
  • 更新时间: 2023-05-11