Multiple fixes for broken master#26
Open
line0 wants to merge 141 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR aims to restore a working “master” by reintroducing missing version-handling functionality, fixing several regressions in module loading and update/feed handling, and adding initial unit-test and line-ending consistency infrastructure.
Changes:
- Added
SemanticVersioningand migrated version parsing/formatting to use it across updater/feed paths. - Fixed/adjusted updater + module-loader behaviors related to initialization and update flows, and added a minimal DepCtrl unit test.
- Updated the project update feed metadata, bumped versions, and enforced LF + final newline consistency.
Reviewed changes
Copilot reviewed 12 out of 15 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| modules/DependencyControl/Updater.moon | Migrates updater version handling to SemanticVersioning and adjusts update logging/changelog display. |
| modules/DependencyControl/UpdateFeed.moon | Adds legacy scriptType compatibility + new invalid scriptType messaging; moves DownloadManager init earlier. |
| modules/DependencyControl/UnitTestSuite.moon | No functional change (newline normalization). |
| modules/DependencyControl/Tests.moon | Adds a first unit test for Common.terms.capitalize. |
| modules/DependencyControl/SemanticVersioning.moon | Introduces semantic version parsing/formatting/comparison utilities. |
| modules/DependencyControl/Record.moon | Switches record version parsing to SemanticVersioning and adds compatibility helpers. |
| modules/DependencyControl/ModuleLoader.moon | Updates init-hook guard logic and switches version formatting/parsing to SemanticVersioning. |
| modules/DependencyControl/FileOps.moon | No functional change (newline normalization). |
| modules/DependencyControl/ConfigHandler.moon | No functional change (newline normalization). |
| modules/DependencyControl/Common.moon | Fixes capitalize() implementation to avoid unsupported string indexing. |
| modules/DependencyControl.moon | Bumps DepCtrl version, exposes SemanticVersioning, and adds a Moonscript minimum-version guard. |
| macros/l0.DependencyControl.Toolbox.moon | Bumps toolbox version; updates version formatting and script-type handling; registers DepCtrl test suite. |
| DependencyControl.json | Updates feed versions/hashes and adds new files (including tests) to the module feed. |
| .vscode/settings.json | Enforces final newline on save in VS Code. |
| .gitattributes | Enforces LF line endings in git. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
line0
force-pushed
the
add-missing-semver-module
branch
2 times, most recently
from
May 23, 2026 22:10
7f7ad69 to
9fee44a
Compare
line0
force-pushed
the
add-missing-semver-module
branch
from
May 23, 2026 22:46
9fee44a to
ad4a5ec
Compare
Comment on lines
57
to
64
| maxVer = SemanticVersioning\toNumber @version | ||
| minVer = SemanticVersioning\toNumber minVer | ||
|
|
||
| changelog = {} | ||
| for ver, entry in pairs @changelog | ||
| ver = DependencyControl\parseVersion ver | ||
| verStr = DependencyControl\getVersionString ver | ||
| ver = SemanticVersioning\toNumber ver | ||
| verStr = SemanticVersioning\toString ver | ||
| if ver >= minVer and ver <= maxVer |
number segments over 255 and non-dot separate values
…r string is passed
line0
force-pushed
the
add-missing-semver-module
branch
from
May 23, 2026 23:14
ad4a5ec to
5bc3f45
Compare
nothing inside DepCtrl is supplying this parameter, so the only effect this bug would have had, is removing the default guard against modules trying to load themselves
- assert now passes through all varargs on success (allows chaining) - new assertNotNil method - fails only on nil, unlike assert which also fails on false - dump/dumpToString methods accept a maxDepth to cap recursive table output - new static Logger.describeType method - returns Lua type name but renders MoonScript class instances as "ClassName object" - fix: guard log/format calls against non-string message templates
…ction to skip tests;
Mechanical rename of the module, its test suite, and all ~180 references ahead of making the class instantiable as a version value. No behavior change. Safe because the class was only split out during the (unreleased) 0.7.0 refactor, so there is no external API to keep compatible. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… bumping Construct a version from a string or numeric components (or via fromPacked); instances compare with </<=/==, stringify, bump immutably, and satisfy ranges. The static helpers accept an instance anywhere they take a version, and the static formerly named toNumber is renamed toPacked to match the instance method. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A new primitive for declaring get/set computed properties on a class:
Accessors.property{get, set} marks a property in the class body and
Accessors.install(class) — called once after the body — rewrites the
instance metatable so reads/writes of those keys dispatch to the getter/
setter, falling through to normal method/field lookup otherwise. A
setter-less property is read-only (a write raises); a subclass that runs
install inherits its parent's properties; every property is recorded on
class.__accessors for inspection tooling. Centralizes the metatable
manipulation in one audited place.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A record's canonical version is now a SemanticVersion value object stored as @semanticVersion, with record.version a packed-integer accessor over it, so existing packed-int reads/writes/comparisons are unchanged. The version is persisted to the config as a "major.minor.patch" string (readable at a glance), migrated from the old packed-integer form on first load; @semanticVersion is initialized up front so a record exposed mid-construction never reads a nil. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
install adds a __pairs metamethod so a readable computed property appears in pairs(instance) with its getter value, like a raw field (under 52compat). Since version then shows up as a packed int while the config stores a string, it's kept out of Record's generic scriptFields copy and serialized explicitly. Inline comments across the rework are tightened per the guidelines. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contribution conventions for DependencyControl: annotation/comment style, file naming, MoonScript gotchas, the public-API and test-exposure patterns, computed properties via Accessors, module-private markers, and changelog rules. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "build macro and module lists" and "create and run the update tasks" comments only restated the immediately following buildDlgList / buildInstalledDlgList / runUpdaterTask calls, which the variable names already convey. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Convert getProgress -> progress (Downloader), getState -> state (Lock), getFailures -> failures (UnitTestSuite) and isPrivate (Host) from methods into read-only computed properties via the Accessors module, updating their call sites: the DownloadManager shim, the depctrl CLI runner, and the tests. Host.isPrivate memoizes into a backing field so repeated reads (and pairs) stay cheap after the one-time resolution. Add LockState/LockScope LuaCATS aliases so the enum-typed field and returns carry named types instead of a bare integer/string with a prose hint, and refresh the now-stale getFailures example in AGENTS.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…overy
- Revert fileBaseUrl/localFileBasePath to plain strings (the
object-valued fileBaseUrl broke v0.3.0 consumers like the DepCtrl
browser) and add fileBaseUrls/localFileBasePaths: per-file-type maps
of full URL/path templates that collapse into the effective
@{fileBaseUrl}/@{localFileBasePath} at each file record, with the
scalars as fallback. The maps roll from any level; DepCtrl's own feed
keeps its dotted macro layout via a macros section override.
- Add @{scriptType}/@{scriptTypeSection}, plus author-defined variables
(root-level vars object) with computed-key lookups —
@{tagSuffix:@{channel}} derives the per-channel release-tag suffix.
Expansion is now brace-aware and runs to a bounded fixpoint.
- Add update-feed --add-files (UpdateFeed.findUnlistedFiles): invert
the effective localFileBasePaths templates, scan the trees beneath,
and append complete entries for unlisted files, attributing types by
longest template prefix. Its first run found six unshipped 0.7.0
files (Accessors, FeedLoader, config-schema + test suites), now in
the feed.
- Fix update-feed --dry-run writing the feed anyway (`dry_run and false
or nil` collapses to nil, i.e. "write").
- Promote the recursive file lister to FileOps.listFilesRecursive.
- Update the v0.4.0 schema, document the template machinery and the
update-feed command in the README, and add unit coverage for
expansion, discovery, and the addFiles flow.
- FileOps: mkdir/rmdir now treat only an explicit error (or an unchanged directory state) as failure. Aegisub's bundled lfs returns nothing on success where LuaFileSystem returns true, so the stricter success check introduced this cycle failed every install inside Aegisub with "failed to create temporary download directory (unknown error)". - Record: uninstall escapes namespace-derived Lua patterns (new Common.escapePattern helper) and anchors them on both sides, so uninstalling a module no longer sweeps a prefix-sharing sibling package (l0.Functional vs l0.FunctionalExtras) into the recursive delete, and hyphenated namespaces no longer match unrelated files. - UpdateTask: install/update messages no longer render "Starting nil of ..." — Common.terms.isInstall is keyed by true/false, but installed records leave `virtual` nil (new getInstallTerm helper). - test.moon: pass basePath to the Record test class; its chunk took no arguments, so basePath silently resolved to a nil global. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… logging - Logger: the window sink no longer repeats the indent prefix on chunks that continue the logger's own open line, so incremental output like the download progress bar renders as one clean bar. The file sink already guarded this via its line-header check; the window sink now uses the existing stream-ownership state the same way. - Toolbox: the startup update sweep relays structured updater statuses (deliberate refusals like unmanaged records, or already-reported run results) verbatim at trace level instead of framing them as "Unexpected error scheduling update"; that framing now only applies to the pcall branch that catches an actual raise. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…g entries - SemanticVersion: route every toString input through toPacked, so nil renders as "0.0.0" and SemanticVersion instances convert instead of both crashing in bit.rshift; a malformed string still returns nil, err. - Toolbox: buildInstalledDlgList treats config entries as the arbitrary on-disk data they are — a missing name falls back to the namespace and an unrenderable version to "?", so orphaned/unmanaged entries get a selectable row instead of erroring the whole picker. - Toolbox: hoist the per-insert table.sort out of both dialog-list build loops. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…path - assertItemsEqual/assertItemsAre: use the (previously dead) itemsEqual failure template with an "equal"/"identical" qualifier — the keys sub-phrase was being passed as the whole message — and type-check the `expected` argument instead of checking `actual` twice. - assertContinuous: check integer *keys* for continuity; it counted integer values, failing continuous tables of strings and passing sparse ones. - assertNotAlmostEquals: report through its own (existing but unused) notAlmostEquals template instead of the assertAlmostEquals text. - assertError: stop counting the pcall status flag among a non-raising function's returned values. - UnitTestSetup: initialize @stubs so ut\stub works inside a _setup. Setup stubs are class-scoped: alive through every test and the teardown, restored when the class finishes (immediately on a failed setup). - Suite run(true): the abort path now stamps @endTime/@success (fixing missing CTRF timings) and logs through msgs.run.aborted — the key it referenced didn't exist, so the Logger silently swallowed it. - Test harness: the silence() helper's no-op logEx now raises on level 1 like the real logger — that raise is the mechanism by which a failing assertion fails its test, so silenced suites could never report failure. The probe and no-op loggers also gained dumpToString, which every assert evaluates eagerly even when passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…me collision - Record.init: the `logsHaveBeenTrimmed` local was written but never read, and init already runs once per Lua state, so trimFiles now runs unconditionally. - UpdateTask.performUpdate: remove the unreachable `@running` guard. Its only caller run() already guards, and firing it here would route through `finish` and clobber the running invocation's state. - Record: rename the static `loadConfig` to `loadGlobalConfig` so it can no longer be silently confused with the instance `loadConfig` of the same name. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The install/uninstall/update pickers each built a sorted display list and its item→record map with the same append-then-sort boilerplate, differing only in how they enumerate their rows. Extract that into `sortedDlgList`, which takes an `add item, record` callback, so `buildInstalledDlgList` and `buildDlgList` supply only their row enumeration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…elpers
The test files each built their own `setmetatable {…}, __index: Class.__base`
stub selves, no-op loggers, and seeded FeedTrust stubs — seven near-identical
factories in test/UpdateTask.moon alone, with more copies in the Updater,
FeedTrust, UpdateFeed, and Record tests. Add test/helpers/stub-helpers with
`stubSelf`, `makeNullLogger`, and `makeSeededFeedTrust`, and route all five
files through them so the fakes stop drifting. `makeNullLogger`'s assert
passes its condition through (and never raises), so assert-guarded code such
as Updater.require keeps working against it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Section defaults were served by two mechanisms: copy-on-write proxies wrapping each top-level default section (the first write into an absent section materialized the whole section's defaults into the user config) and the per-key mergeSection fallthrough for sections already present. Serve both cases through mergeSection: it now binds to the view's live userConfig and section key, so a held section view survives a refresh or load replacing that table, and a first write into an absent section creates it sparsely with just the written key — defaults are never materialized into stored config. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…perty Each feed instance replaced its metatable with a fresh closure table just to synthesize `url` from `_url` or the local file name, allocating a metatable per feed and breaking `getmetatable(feed) == UpdateFeed.__base` identity. Declare `url` as a read-only Accessors computed property instead: reads behave as before, instances keep the shared class metatable, and a write to `url` (which previously shadowed the synthesized value via rawset) now raises. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The loading methods disagreed on their failure shape: fetch and loadFile returned false plus an error, ensureLoaded returned either nil or false depending on the failing leg, and even UpdateFeed's own wrappers handled the result inconsistently. All three now return nil plus the error message. getScript's false is untouched: it distinguishes "not in this feed" (false, no error) from a real failure (nil, err), and checkFeed relies on that. The constructor keeps its documented raise — a MoonScript constructor's return value is discarded, so it cannot report nil, err. fetch's failure value shipped as false in 0.6.3; every known caller checks truthiness, so the change is noted in the changelog rather than kept as a permanent inconsistency in the frozen API. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… flow; isolate ManageFeeds from the network The ManageFeeds tests drove the real offline gather against the live trust singleton, whose official-set load fetches the DepCtrl feed over the network on a cold cache — a class setup now seeds both official accessors so no test run leaves the process. New coverage: the startup sweep (per-record scheduling, module test-menu registration, tolerance of a raising or refusing scheduleUpdate, lock release) via scheduleUpdatesAndRegisterTests moving above registerMacros to join the test exports; the uninstall result shapes (success, string error, per-file error table, locked files) through a construction seam that swaps the class __call in a setup/teardown pair, since LuaJIT requires a metamethod to be a plain function and a Stub cannot stand in; and the Manage Feeds Block flow (reason prompt travels in the action options, declining the sourced-packages warning abandons the block). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…states Replicates Aegisub loading one DependencyControl copy per automation script in isolated Lua environments at the same time — the scenario the Logger's seed sleep exists for. Overlapping luajit child processes each seed through the real Logger construction and report the head of their random stream, which must be unique per state; self-gates where a child process can't be spawned. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
First Logger construction slept half a second (10ms x 50) per Lua state purely to spread math.randomseed apart across simultaneously loading scripts — the single largest avoidable startup cost DependencyControl added to every script. The monotonic clock's sub-microsecond reading already diverges per state, and adding the pid separates whole processes, so the seed needs no waiting at all; the per-state Timer instance existed only for this and is gone too. The LoggerIntegration guard proves the divergence property across overlapping isolated states with the sleep removed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
line0
force-pushed
the
add-missing-semver-module
branch
from
July 18, 2026 00:03
f877e92 to
bab4f69
Compare
line0
force-pushed
the
add-missing-semver-module
branch
from
July 18, 2026 01:09
bab4f69 to
c985d61
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR fixes several issues, largely caused by the incomplete refactoring some 10 years ago:
__depCtrlInithooks were called again on - already-initialized modules, causing errors in modules that mutate their exported state on - first call (e.g., BadMutex).,true/falsescript type arguments were - no longer accepted after theScriptTypeenum migration.,DownloadManagerwas instantiated too late, causing the - update process to fail.capitalize()function no longer uses unsupported string indexing and now works - for the first time ever. Before the refactor, this was previously masked by it not actually - being called anywhere.Additionally, i have added a unit test suite for DepCtrl (only 1 tiny test for now) and made all files use LF + EOF Newline to ensure consistent file hashes.