feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on. - project.cpp: a static crafter.review-lib and the crafter-review executable; Crafter.Network without QUIC, pinned, or with --local from the checkout next to this one; Crafter.LintRules' lite rules, pinned; the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev. - :Core and :Driver: the version, PromptVersion 1, --version. - :Json: nlohmann's ordered_json, which keeps key order and unknown keys, so the files every driver on a machine shares survive a rewrite; dumps in the indented file layout, the spaced one-line form and the compact sorted form the structured-output schema needs byte for byte. - :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and base32 written out, because what they refuse, and with which message, is pinned. - :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal digits, printable characters, case mappings and case-insensitive folds. - :Text: string functions on code points, number parsing, the shortest float form and half-even rounding, printed values, shell patterns, URL splitting and unquoting, POSIX paths, universal newlines and the replacing UTF-8 decoder. Tests: Crypto (published vectors), Text (293 reference vectors). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e176dc87b5
commit
36852edf63
16 changed files with 7845 additions and 0 deletions
103
project.cpp
Normal file
103
project.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||||
|
||||
import std;
|
||||
import Crafter.Build;
|
||||
// Pinned: the Flatpak builds with the base app's crafter-build, which can be
|
||||
// older than the rules' master. Move the pin together with the base.
|
||||
#pragma crafter dependency "https://forgejo.catcrafts.net/Catcrafts/Crafter.LintRules.git" commit "7d932892017800b4e1f1a15fe7aa49b3daee9ceb"
|
||||
import Crafter.LintRules;
|
||||
namespace fs = std::filesystem;
|
||||
using namespace Crafter;
|
||||
|
||||
namespace {
|
||||
// The umbrella, then the partitions in import order: each after the ones
|
||||
// it imports, which is also the order the module map in AGENTS.md uses.
|
||||
constexpr std::array<std::string_view, 7> Interfaces = {
|
||||
"interfaces/Crafter.Review",
|
||||
"interfaces/Crafter.Review-Unicode",
|
||||
"interfaces/Crafter.Review-Json",
|
||||
"interfaces/Crafter.Review-Text",
|
||||
"interfaces/Crafter.Review-Crypto",
|
||||
"interfaces/Crafter.Review-Core",
|
||||
"interfaces/Crafter.Review-Driver",
|
||||
};
|
||||
constexpr std::array<std::string_view, 4> Implementations = {
|
||||
"implementations/Crafter.Review-Text",
|
||||
"implementations/Crafter.Review-Crypto",
|
||||
"implementations/Crafter.Review-Core",
|
||||
"implementations/Crafter.Review-Driver",
|
||||
};
|
||||
|
||||
// One per directory under tests/, each an ordinary main() that links the
|
||||
// library: exit 0 passes, nonzero fails, 77 skips.
|
||||
constexpr std::array<std::string_view, 2> Tests = {
|
||||
"Crypto",
|
||||
"Text",
|
||||
};
|
||||
|
||||
// The version the binary reports: CI sets it from the tag, a checkout
|
||||
// describes itself, anything else is a development build. A define on
|
||||
// the library, so each version is its own library variant.
|
||||
std::string Version() {
|
||||
if (const char* env = std::getenv("CRAFTER_REVIEW_VERSION"); env && *env) return env;
|
||||
auto described = RunCommandWithTimeout("git describe --tags --always --dirty --exclude=latest 2>/dev/null", std::chrono::seconds(10));
|
||||
std::string version = described.output;
|
||||
while (!version.empty() && (version.back() == '\n' || version.back() == '\r')) version.pop_back();
|
||||
if (described.exitCode != 0 || version.empty()) return "0.0.0-dev";
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
|
||||
// Crafter.Network for its TCP and HTTP/1.1 clients and listener, without
|
||||
// QUIC: msquic is most of a fresh build and nothing here speaks HTTP/3.
|
||||
// From forgejo at a pinned commit, or with --local from the checkout next
|
||||
// to this one (which is also how Crafter.Network then finds
|
||||
// Crafter.Thread).
|
||||
std::vector<std::string> depArgs(args.begin(), args.end());
|
||||
depArgs.emplace_back("--no-quic");
|
||||
const bool useLocal = std::ranges::find(args, std::string_view("--local")) != args.end();
|
||||
Configuration* network = useLocal
|
||||
? LocalProject({ .projectFile = "../Crafter.Network/project.cpp", .args = depArgs })
|
||||
: GitProject({
|
||||
.source = { .url = "https://forgejo.catcrafts.net/Catcrafts/Crafter.Network.git", .commit = "f68321685006be65f6bc0436fd0175611f1e0a55" },
|
||||
.args = depArgs,
|
||||
});
|
||||
|
||||
static auto ReviewLib = std::make_unique<Configuration>();
|
||||
ReviewLib->path = "./";
|
||||
ReviewLib->name = "crafter.review-lib";
|
||||
ReviewLib->outputName = "crafter-review";
|
||||
ApplyStandardArgs(*ReviewLib, args);
|
||||
ReviewLib->type = ConfigurationType::LibraryStatic;
|
||||
ReviewLib->dependencies = { network };
|
||||
// Backslash-escaped quotes: the define travels through the shell before
|
||||
// it reaches clang, which must still see a string literal.
|
||||
ReviewLib->defines.push_back({"CRAFTER_REVIEW_VERSION", std::format("\\\"{}\\\"", Version())});
|
||||
{
|
||||
std::vector<fs::path> interfaces(Interfaces.begin(), Interfaces.end());
|
||||
std::vector<fs::path> implementations(Implementations.begin(), Implementations.end());
|
||||
ReviewLib->GetInterfacesAndImplementations(interfaces, implementations);
|
||||
}
|
||||
|
||||
Configuration cfg;
|
||||
cfg.path = "./";
|
||||
cfg.name = "crafter.review-exe";
|
||||
cfg.outputName = "crafter-review";
|
||||
ApplyStandardArgs(cfg, args);
|
||||
cfg.type = ConfigurationType::Executable;
|
||||
cfg.dependencies = { ReviewLib.get() };
|
||||
{
|
||||
std::array<fs::path, 0> interfaces = {};
|
||||
std::array<fs::path, 1> implementations = { "implementations/main" };
|
||||
cfg.GetInterfacesAndImplementations(interfaces, implementations);
|
||||
}
|
||||
|
||||
for (const std::string_view test : Tests) {
|
||||
cfg.AddTest(test).Dependencies({ ReviewLib.get() });
|
||||
}
|
||||
|
||||
LintRules::AddLiteRules(cfg);
|
||||
return cfg;
|
||||
}
|
||||
Loading…
Reference in a new issue