Repository navigation
refactor: services hand out the state a run owns - #93
Merged
Merged
Conversation
ConfigService kept one invocation's configs on a process-wide service, and the watch learned what a reload changed by draining onDidChangeConfig. select(args, scope) now hands out a ConfigSelection that the command or the watch session holds, and its reload returns what changed and which errors are new, so a config that breaks is reported without the log de-duplicating config problems. ConfigEntry is a valid | broken union, ResolvedConfig carries its parents and skipped tags, and RebuildReport drops its entry. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…build's values Commands sequenced requireBuildable then run, and the watch asked the service for blockedConfigs; build-service.ts was a type dump its own internals imported. build(selection) now checks validity and the set rule itself, rebuild(config) is the watch's one-config step, and locate(selection) answers every config with whether every file was asked about. The set rule is BuildBlockers, a value in build.ts beside the match, left-out, summary and location types and OutputFile, so the watch asks it directly and watch(selection) refuses what build would. BuiltProject.placement, which nothing read, is gone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
IndexService held one tree for the process with two lifecycles: ensureIndexed grew it for one-shot commands, and initialize and applyChanges replaced and edited it for a watch, across awaits a rebuild could read through. list(dirs) now returns a Listing and update(listing, changes) a new one, copying only the directories it edits. A build or locate lists the root dirs it reads once; the watch session holds its listing, replaces it on its intake, and rebuild(config, listing) reads the one it started with. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nswers it The build read its sync tools through ToolchainService.getSyncTools, and Darklua and RobloxTsCompiler each played a build role beside an init one, so roblox-ts had a compiler constructed without facts just to tell the build what it emits. SyncTool and MetaReplacement now live in build.ts; Darklua.SYNC_TOOL and ROBLOX_TS_SYNC_TOOL are the answers, CoreToolchainService lists them, and main.ts hands them to CoreBuildService. The build no longer imports the toolchain, and ToolchainService is detect alone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…f its update The session kept a config's rebuild queue, whether it failed, what its build read and a global rebuild count in four parallel fields. WatchedConfig holds them for one config and derives "settled" from its latest build, so the filter that drops source updates no build read asks each config. The batcher no longer logs: an overflow carries how many changes it dropped, the burst cause carries that, and WatchLog prints the warning when it reports the round, so the watch module takes no LogService. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ames have one home The validator re-walked every root and reading to find the names that differ from a declared key only in letter case, which NameReadings had already found; it now records them as it reads. The name Rojo gives an entry, the file whose name carries its suffixes and the sources behind an init folder were each worked out from the entry's kind in a different stage; rojoNameOf, namingFileOf and membersOf now sit beside ScannedEntry. Placement derives the files the template displaced from its left-out paths instead of being handed a second copy. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… them init rendered config files with its own $schema line, the schema and the RogenConfig shape could drift apart, and the path fields were listed in three places. configFileContent renders a config the way Rogen writes one, the schema is built from one entry per RogenConfig field, and PATH_FIELDS is the list that absolutizing, the command-line tier and the single-config rule read. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ask() wrote private optional state that plan() read back behind "planned only once it was asked" throws, PlaceSetup had a private constructor with two factories that set different halves of it, and ProjectSetup carried a KnownProject and an answers getter only tests used. Setup<C> now has ask(): C | undefined and plan(choices, builder), so a plan can't be made without answers; a place's choices hold what it joins, ProjectChoices holds the copied template, and CoreInitService runs any setup through one planWith. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
InitDirectory carried the file system and config services so any setup could read the base config, a sync config's sync dir or a template to copy through it. It now holds the base config CoreInitService read up front with BaseConfigReader, which also owns the rule that a Darklua repo's sync dir is on the synced config; ProjectSetup reads the template it copies itself. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…he file system Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
createDirectory over a file fails, delete under a missing parent does nothing, and a write reports the directories it creates. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The workspace names the Darklua config it found, so the prompt hints at the right file, and ConfigSet and the setups hold the Darklua they use instead of asking the workspace for it again. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… compiled code The place's sync dir now follows ConfigSet.syncDir, as the project's does, instead of preferring the compiler's output when its config sets none. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
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.
Services that created state for one run held it as a singleton. Now they hand it out as a model the caller owns. Behind that, the domain and platform layers are cleaned up wherever ownership was unclear.
What changes
ConfigService.select(args)returns aConfigSelectionthat the caller owns.validorbroken, and a broken entry keeps its last valid version.reload(files)returns{ changed, notices }.initializeandAbstractConfigServiceare removed, andWatchLogno longer deduplicates config problems itself.IndexServiceislistandupdate, and returns an immutableListing. A build lists the files itself, and a watch holds its own listing and updates it.BuildServiceisbuild(selection),rebuild(config, listing)andlocate(selection).whereuses the same builder asbuild. The shared types (ConfigBuild,Locations,OutputFile,SyncTool,BuildBlockers) are inbuild.ts.SyncToolis defined in build. Toolchain supplies the values andmain.tspasses them to the build, so build doesn't import toolchain. EachLanguagehas its own init text.WatchedConfigrecord.ChangeBatcherno longer takes aLogService; it emits aChangeBurst, andWatchLogprints the warning.Setup<C>objects (askand thenplan), andInitDirectoryis pure.Darkluaobject rather than a boolean, and the workspace records which Darklua config file it found.DiskWatcheralso uses.createDirectoryover a file fails,deleteunder a missing parent does nothing, and a write reports each directory it creates.Behavior changes
.darklua.json5when that is the file present).dist/<place>) when the base config sets no sync dir. Before, it synced from the compiler's output.Not in this PR
Processorinterface: Darklua is the only processor.MemoryFileSystemServiceimplementingWatcher.NullLogServiceextendingAbstractLogService.AbstractWatcher.Open questions
main.tspasses one table for all configs.wherestill fails on a config that declares no routes.PlaceSetupdecides whether to use Darklua from whether a.darklua.jsonexists, not from how the project was set up. This was already the case before this PR.Testing
tsc,eslintand 2077 jest tests (unit and e2e) pass on every commit.🤖 Generated with Claude Code