25 Commits
Author SHA1 Message Date
手瓜一十雪 a434da9e85 Skip resolveImports for files without subclasses
Add a cheap AST probe in file-pipeline to detect if a file contains extending classes (using fileHasExtendingClass) and return early to avoid the expensive resolveImports recursive descent when not needed.

Update subclass-wrapper tests to import beforeAll and cache the plugin transform output and its stripped JS once in a beforeAll hook, replacing repeated transform calls with reused transformedOutput/strippedJs to reduce test runtime.
2026-05-26 22:02:31 +08:00
手瓜一十雪 2c565fbd8d Switch from @snowluma/sqlite to node:sqlite (sync)
Remove the in-tree @snowluma/sqlite wrapper and vendored better-sqlite3 prebuilts; migrate consumers to node:sqlite's synchronous API. Replaced imports and types (Database/Statement -> DatabaseSync/StatementSync), updated PRAGMA calls to use exec, and adjusted code in onebot (media/message/reaction stores) and protocol (identity service). Vite config no longer bundles sqlite native binaries and references to the sqlite workspace were removed. Also delete the packages/sqlite package and its native prebuild artifacts, and add a couple of unrelated AST improvements in proton: use a module-level shared wrapper cache and add an inheritance cache to avoid repeated scans. Minor import reordering/cleanup applied where needed.
2026-05-26 21:59:26 +08:00
手瓜一十雪 0d30ee628e Switch subclass-wrapper to AST-only pipeline
Refactor subclass-wrapper resolution to an AST-only pipeline and remove the TypeChecker-based program cache.

- Move subclass-wrapper logic from typecheck/ to ast/: add ast/file-pipeline.ts and ast/subclass-wrapper.ts, and update codegen/imports accordingly.
- Implement AST-only cross-file extends resolution using import-resolver's fileCache (findImportSourcePath) and a WrapperLookupCache; subclass methods must now have explicit type annotations (no TypeChecker inference).
- Remove TypeChecker-dependent program-cache and typecheck/file-pipeline; plugin no longer preloads a ts.Program or accepts tsconfig option.
- Simplify plugin cache startup and HMR handling in src/index.ts to use the AST pipeline and transform cache only.
- Update tests to use the new AST pipeline entrypoints and adjust expectations.

This eliminates the dependency on a baked ts.Program for wrapper resolution, simplifies startup, and relies on the existing import-resolver for cross-file traversal. Partial wrapper resolutions are still all-or-nothing; explicit annotations are required for AST-only resolution.
2026-05-26 21:48:12 +08:00
手瓜一十雪 0f7aa5a600 Refactor import & wrapper typecheck APIs
Consolidate and simplify import extraction and wrapper/typecheck internals. Introduce collectImportClauses that drives both type+value and value-only import extraction with per-file caching; reintroduce extractImports/extractValueImports as thin wrappers. Clean up BARE_SPECIFIER_COMPILER_OPTIONS comment. Replace the containsTypeParameter/firstTypeParameterIndex pair with a single findTypeParameterIndex helper. Remove collectExportedWrappers and call collectWrappers directly from parseFileForDefinitions; ensure imported wrapper collection skips type-only imports to avoid eager parsing.

Streamline static-wrapper representations: ClassWrapperInfo is now a Map<string, WrapperMethodInfo>, and related detection helpers updated and documented. Simplify subclass-wrapper/typechecker APIs: drop wrapperOwner and SourceFile parameters where unused, adjust function signatures (collectInheritedWrappers, resolveSubclassWrappers, resolveWrapperCodecCalls, extractSubclassMemberTypeNode) to operate with fewer arguments and return plain WrapperMethodInfo lists. Update file-pipeline to match reordered args.

Refactor plugin context creation: add buildContext helper, createPluginContext/createStandaloneContext now delegate to it; remove programPrepared flag and adjust prepareProgramForTsconfig invocation site. Update tests to reflect Map API changes and revised function signatures.

Overall this is an internal refactor to reduce duplication, avoid eager work for type-only imports, remove unused params, and clarify interfaces without changing behavior.
2026-05-26 21:24:37 +08:00
手瓜一十雪 1b07005d91 Unify protobuf helpers and tidy comments
Export and centralize small utility helpers and remove duplicate implementations: identityImportedTypeName was exported from utils, and isVarint64/isFixed64BigInt were added to types and imported into encoder/decoder. Minor import reorders and formatting cleanups across collector, monomorphizer, import-resolver, static-wrapper, subclass-override and file-pipeline. Comments and JSDoc were tightened for clarity; behavior remains the same but common logic is now deduplicated and easier to maintain.
2026-05-26 20:53:32 +08:00
手瓜一十雪 c3a8a9b6b6 Revert "Add transform + program caching to plugin"
This reverts commit 868f4a5798.
2026-05-25 12:02:22 +08:00
手瓜一十雪 868f4a5798 Add transform + program caching to plugin
Introduce disk caching and startup program preparation for the Proton Vite plugin. Add ProtobufVitePluginOptions (root, tsconfig, cache) and configResolved hook to prebuild/prepare a TypeScript Program (program cache) and create a transform cache per-file (transform cache) keyed by source/config hashes and dependency mtimes. Track dependencyFiles in import-resolver so transform cache can validate mtimes. Update program-cache to support incremental tsbuildinfo and expose prepareProgramForTsconfig. Add cache read/write, hashing, path normalization and scope checks in the plugin; update tests and README to cover scope and cache behavior. Also add ts-morph dependency and update lockfile.
2026-05-25 11:52:46 +08:00
手瓜一十雪 93850ec11c Add text-edit utility and import resolution caches
Introduce a TextEdit type and applyTextEdits utility for safe, reverse-ordered string edits and refactor replacer to produce and consume edit lists (collectReplacementEdits) instead of performing manual slicing. Propagate ts.SourceFile through ParsedFileEntry/ImportedDefinitions and use cached extraction of imports/exports to avoid repeated AST traversal when resolving imports; analyzer now prefers an imported sourceFile when available. Wire text edits into the plugin pipeline (compose replacement + override edits) and remove the previous applyOverrideInsertions helper. Add a tsconfig lookup cache in program-cache to speed up upward tsconfig searches and invalidate it when the program cache is cleared. README updated to list the new files.
2026-05-25 11:42:03 +08:00
手瓜一十雪 40c51bcd02 Extract wrapper binding logic to wrapper-binding.ts
Move instantiateWrapperTypePattern and the WrapperBinding type into a new wrapper-binding.ts module and register it for reuse. Update analyzer.ts and import-resolver.ts to import the function/type from the new module and simplify call-site/type-root collection logic (use entrySourceFile and a cached callable name). Also update README: add ast-helpers.ts and wrapper-binding.ts to the file list and bump test count in the example.
2026-05-25 11:34:37 +08:00
手瓜一十雪 bed48bbe46 Skip subclass-wrapper pipeline when no subclasses
Avoid the expensive TypeChecker/program startup for files that don't declare extending classes by performing a cheap top-level scan first. index.ts now imports fileHasExtendingClass and a SubclassWrapperPipelineResult type and conditionally calls runSubclassWrapperPipeline only when a candidate is found, otherwise returning an empty result. Also updated comments to explain the optimization. subclass-wrapper.ts now imports isStaticMethod from ast-helpers.js (small import cleanup/usage update).
2026-05-25 11:30:41 +08:00
手瓜一十雪 34cc6be8df Add AST helpers, cache resolver, translate README
Add shared AST predicates in packages/proton/src/ast/ast-helpers.ts to centralize small structural checks used by the analyzer, callsite matcher, wrapper detector, and subclass resolver. Introduce a WeakMap cache in packages/proton/src/ast/utils.ts so createImportedTypeNameResolver is memoized per SourceFile to avoid repeated import-scans during transform() work. Update packages/proton/README.md with a Chinese translation and various clarifications/documentation tweaks.
2026-05-25 11:28:05 +08:00
手瓜一十雪 c55042aff4 Splice subclass override code into source
Group rendered subclass overrides per class and emit them as position-tagged insertions instead of a single trailing string. Add SubclassOverrideInsertion and applyOverrideInsertions to splice overrides immediately after each subclass declaration (sorted in reverse to keep offsets valid). Update runSubclassWrapperPipeline to collect per-subclass rendered parts and return insertions + extra root names, and update the plugin transform to apply these insertions before producing final code. Update tests to expect insertions and verify placement and runtime behavior. This ensures user code sees overrides right after the class body so subsequent top-level calls dispatch to the override rather than an inherited abstract implementation.
2026-05-25 11:20:44 +08:00
手瓜一十雪 3726913c1f Support per-subclass static wrappers; drop runtime map
Introduce per-subclass static-method wrapper support: detect wrapper-pattern methods in the AST, resolve concrete types via a TypeChecker, render per-subclass overrides, and append them into transformed output. Adds static-wrapper detector, subclass-override codegen, a typecheck file pipeline, a lazy ts.Program cache, and the subclass-wrapper resolver. Integrates the pipeline into the Vite plugin (including program cache invalidation on HMR) and threads extra root type names into registry selection so generated overrides get required codecs. Remove the runtime-map fallback feature and related types/logic (runtime-map module, dynamic runtime generation, and public API surface), simplifying runtime stubs and protobuf.d.ts. Update README and analyzer to document and support the new flow; add tests and fixtures for subclass-wrapper behavior.
2026-05-25 11:17:31 +08:00
DrSmoothl 5924346823 chore(release): v1.9.2 2026-05-24 18:01:50 +08:00
手瓜一十雪 80ee12ecc2 Enforce no-explicit-any; allow in tests
Enable @typescript-eslint/no-explicit-any as an error in the ESLint config to tighten typing across the codebase, and add an override to disable this rule for test files. Also apply non-functional cleanup in packages/proton/src/runtime.ts: reorder/imports and adjust formatting/indentation and string alignment for readability — no behavioral changes.
2026-05-24 13:38:13 +08:00
DrSmoothl 607a7b319b chore(release): v1.9.1 2026-05-21 17:33:35 +08:00
DrSmoothl 994633eafa feat(proton): resolve bare specifiers via TypeScript module resolution
`resolveModulePath` used to skip any specifier not starting with '.'
which meant proton's vite plugin only saw proto definitions that lived
in the same package as the call site. Trying to move definitions into
a sibling workspace package (e.g. `@snowluma/proto-defs`) caused those
imports to silently fail — the call-site type lookup found nothing
and the protobuf_encode<T> replacement never fired.

Add a bare-specifier branch that delegates to `ts.resolveModuleName`
with `moduleResolution: Bundler`. That covers monorepo workspaces,
npm packages, package.json `exports`, and tsconfig path aliases with
zero extra user configuration.

The relative-path branch is preserved byte-for-byte so existing
single-package consumers see identical behaviour. Resolution is
constrained to `.ts` source files (not `.d.ts`) because proton walks
interface AST to collect `pb<>` field tags, and generated declaration
files typically strip those generic arguments.

Per-process `ModuleResolutionCache` keeps the hot path (HMR rebuild)
from re-scanning node_modules every call.

Tests: new `cross-package.test.ts` builds a fake monorepo under
`os.tmpdir()` and exercises smoke / transform / round-trip / negative
paths. 99/99 proton tests pass; SnowLuma core regression unchanged
(587 baseline ⇄ 587 with change).
2026-05-20 21:22:48 +08:00
手瓜一十雪 36c3ed031b Apply formatting and fix web request utilities
Add consistent indent rule to ESLint and normalize formatting/indentation across multiple files. Refactor RequestUtil: improve cookie extraction, redirect handling, and HttpGetJson/HttpGetText request flow; fix cookie string builder formatting. Fix uploadGroupNoticeImage promise/error handling and network request flow. Also apply minor style/refactor tweaks in bridge web APIs, onebot handlers, message-store SQL alignment, and Proton AST collector utilities to improve readability and correctness.
2026-05-20 19:16:06 +08:00
手瓜一十雪 aea2676c31 Add TypeScript ESLint configs and lint scripts
Add a repository .editorconfig and a root eslint.config.ts to standardize formatting and linting. Migrate packages/webui ESLint config to TypeScript (eslint.config.ts) with project-specific rules and tsconfigRootDir handling, and remove the old JS config. Update package.json to run ESLint directly (add lint and lint:fix) and add required ESLint/dev dependencies; also add jiti to packages/webui/package.json. Include a small formatting tweak to tsconfig.base.json.
2026-05-20 19:08:45 +08:00
手瓜一十雪 f21740a5d3 Support types re-exported via export *
Add support for resolving types re-exported with `export * from '...'`. Introduces extractExportAllSpecifiers and a new exportAllTypeSources map on ParsedFileEntry, populates it while parsing (recursively following export-all chains using the cache and an inProgress set to avoid cycles), and falls back to exportAllTypeSources when resolving imported type names. This allows types and generic templates exported through export-all declarations to be discovered and resolved.
2026-05-20 18:37:58 +08:00
DrSmoothl 2de1ff4f0d chore(release): v1.9.0 2026-05-20 14:21:03 +08:00
DrSmoothl 5802812392 feat(proton): finish OIDB migration — runOidb on protobuf_encode<OidbBase<T>>
Closes the OIDB phase of the proton migration. Every consumer that
talked to the OIDB service through the old runtime
`makeOidbBaseSchema()` factory now goes through the compile-time
generic `OidbBase<T>` instead — proton monomorphizes the codec per
call-site instantiation.

@snowluma/proton — two analyzer fixes uncovered by the migration:

1. Skip queuing call-site type-args that reference an *enclosing
   generic function's* type parameter for monomorphization. Before
   this, a wrapper like

     export function encodeOidbEnv<T>(env: OidbBase<T>): Uint8Array {
       return protobuf_encode<OidbBase<T>>(env);
     }

   would cause the analyzer to mint a literal `OidbBase__T` registry
   entry with `body.typeName = 'T'`, which the post-walk wire-type
   guard then tripped on. The enclosing-scope type params are tracked
   on a stack as the walker descends into FunctionDeclaration,
   FunctionExpression, ArrowFunction, MethodDeclaration nodes; matching
   call sites are skipped (the wrapper-binding path is still
   responsible for materialising concrete codecs at downstream call
   sites).

2. Register *explicitly* empty interfaces (`interface X {}`) as
   zero-field proto messages. OIDB has a handful of these
   ('this call has no meaningful response body' placeholders —
   Oidb0xeb7Resp, Oidb0xcd4Resp, Oidb0x112aResp, Oidb0x8a0Resp,
   Oidb0xf16Resp, OidbClientKeyReq). Proto3 wire allows zero-field
   messages, and downstream code does `protobuf_decode<OidbBase<X>>`
   where X is one of these — the wire-type guard would otherwise trip
   on the missing `X` registration. Interfaces that have members but
   no pb-marked fields are still NOT registered.

@snowluma/core — the OIDB-layer refactor itself:

bridge-oidb.ts ditches the runtime ProtoSchema factory and exposes:
  - makeOidbEnvelope<T>(oidbCmd, subCmd, body, isUid)   pure helper
  - encodeOidbEnv<T>(env)                               pass-through
  - decodeOidbEnv<T>(bytes)                             pass-through
  - runOidb(bridge, cmd, envelopeBytes)                 non-generic raw

`encodeOidbEnv` / `decodeOidbEnv` are pure pass-through generic
wrappers — proton wrapper-binds them and substitutes every call site
with the inlined `protobuf_encode_OidbBase__X` / `protobuf_decode_…`
function. `runOidb` is non-generic (proton leaves it alone) so it can
be mocked in tests. `makeOidbEnvelope` is plain TS — also mockable for
introspection.

56 `runOidb` call sites across 11 files migrated to the new API:
  - bridge-contacts.ts, actions/extras.ts, actions/friend.ts,
    actions/group-admin.ts, actions/group-file.ts,
    actions/group-message.ts, actions/interaction.ts,
    actions/misc.ts, actions/profile.ts, web-actions/cookies.ts,
    highway/pipeline.ts

pipeline.ts also drops `makeOidbBaseSchema(NTV2UploadRichMediaReqSchema)`
and the residual `protoEncode({...}, EncodableMediaMsgInfoSchema)` —
both go through proton now.

Tests:
  - 8 test files migrated from `vi.mocked(decodeOidbEnv).mockReturnValueOnce`
    to `vi.mocked(runOidb).mockResolvedValueOnce(protobuf_encode<OidbBase<X>>({body: …}))`
    — the proton substitution means the old mock layer is bypassed at
    build time, so the only mockable point is the bytes layer at `runOidb`.
  - 2 new parity tests pinning `OidbBase<T>` ↔ legacy
    `makeOidbBaseSchema(InnerSchema)` byte equivalence.

Verification:
  - @snowluma/proton: 95/95 tests pass, tsc --noEmit clean
  - @snowluma/core:   605/605 tests pass (network-manager.test.ts
    fails to load due to a missing darwin-arm64 native binary in this
    environment — pre-existing), tsc --noEmit clean
2026-05-19 08:19:14 +08:00
DrSmoothl 31079673c6 docs(proton): add README
Covers quick start, primitive types, generic templates, cross-file
wrapper bindings, the proto3 default-value divergence vs the legacy
runtime encoder, build-time diagnostics, and the optional runtime-map
fallback. Also lists every edge case fixed on top of upstream with a
pointer to the corresponding regression test.
2026-05-19 08:19:14 +08:00
DrSmoothl 3d739c255a feat(proton): proof-of-concept migration — longmsg parity test
Migrates a self-contained subset of bridge/proto/longmsg.ts to the new
@snowluma/proton compile-time DSL form and verifies wire-format parity
against the legacy runtime ProtoSchema encoder. End-to-end proof that
the toolchain works in core's vitest pipeline.

What's covered:
  - LongMsgUid / LongMsgSettings / SendLongMsgInfo / SendLongMsgReq /
    SendLongMsgResp / SendLongMsgRespResult / RecvLongMsgInfo /
    RecvLongMsgReq / RecvLongMsgResp / RecvLongMsgRespResult
  - The three schemas that pull in PushMsgBody (LongMsgContent /
    LongMsgAction / LongMsgResult) stay on the legacy API for now, since
    migrating them requires also migrating message.ts and element.ts.

Toolchain changes:
  - @snowluma/proton gets a tsup build step. The ./vite subpath now
    points at the built dist/index.js so it is loadable as plain Node
    ESM from vite.config.ts / vitest.config.ts (the source-only .ts
    layout can't be consumed from outside the Vite transform pipeline).
    The . (runtime) subpath stays at TS source — it's only ever
    imported from user code, which IS Vite-transformed.
  - prepare script ensures dist/ exists after pnpm install.
  - @snowluma/core depends on @snowluma/proton (workspace:*) and adds
    protobufVitePlugin() to its vitest config so test files get
    transformed.

Documented divergence:
  proton follows proto3 semantics: fields equal to their default value
  (0 / false / "" / empty bytes) are NOT emitted on the wire. The legacy
  runtime encoder always emits them. Both forms are round-trippable
  through a conforming proto3 reader. The parity test pins this
  behaviour explicitly.

8/8 parity tests pass.
2026-05-19 08:19:13 +08:00
DrSmoothl 194165f49d feat(proton): add @snowluma/proton — compile-time protobuf DSL
Vendors SnowLuma/protobuf-dsl into the monorepo as @snowluma/proton, with
edge-case fixes applied on top of the upstream source. Reference copy of
the unmodified upstream is kept under dev/protobuf-dsl/.

Edge cases fixed (each with a regression test):
  - Aliased pb / pb_repeated marker imports (`import { pb as P }`)
    — collector now resolves the marker name through the import resolver
  - Concrete interface with a generic-instantiated message field
    (`wrapped: pb<5, Wrapper<uint_32>>`) — field typeName now resolves
    to the mangled form, and the inner instantiation is queued for
    monomorphization
  - Generic template with a generic-instantiated field
    (`interface Outer<U> { x: pb<5, Wrapper<U>> }`) — the inner
    instantiation is now re-substituted and re-monomorphized at outer
    instantiation time
  - Wrapper-binding synthetic SourceFile was empty-text — getText()
    returned garbage, breaking mangled name computation downstream
  - Cross-file forwarded wrappers (chain → imported base) were not
    detected — parseFileForDefinitions now resolves imports recursively
    (value imports only, with cycle protection)
  - matchForwardedKnownWrapper did not propagate typePattern — chain
    treated <X> as the encoded type instead of Wrapper<X>
  - Synthetic-SF WeakMap was private to analyzer.ts — replacer could
    not see it. Moved to utils.ts so typeNodeToMangledName picks it up
    automatically.

Defensive guard: any field whose typeName resolves to neither a primitive
nor a known message now throws at analyze() time, instead of silently
leaking the WireType.Varint placeholder into codegen.

95/95 tests pass; tsc --noEmit clean.
2026-05-19 08:19:13 +08:00