fix: deterministic LF line endings for generated files#1477
Draft
joaodinissf wants to merge 4 commits into
Draft
fix: deterministic LF line endings for generated files#1477joaodinissf wants to merge 4 commits into
joaodinissf wants to merge 4 commits into
Conversation
The keyword diagnostic/report writers used PrintWriter.println, whose terminator is the platform separator — the one raw-IO emission path the FSA-level LF normalization never covers (dsldevkit#1345; revives the KeywordAnalysisHelper piece of the closed dsldevkit#1354). All println(...) overloads terminate via println(), so a minimal LfPrintWriter override of that single method makes every call site emit LF; the report builders themselves already append '\n' literals. Assisted by Claude
ModelInference.mwe2 and TypeModel.mwe2 were the last MWE2 workflows generating committed src-gen without an explicit lineDelimiter — their three EcoreGenerator components fell back to the platform default, so regenerating on Windows would produce CRLF diffs against the LF policy. Completes dsldevkit#1413's coverage; CustomClassAwareEcoreGenerator already forwards getLineDelimiter() into the EMF generator adapter. Assisted by Claude
…atorInformation Xtext's LineSeparatorHarmonizer post-processes every text IFileSystemAccess write and owns the final bytes, but its default ILineSeparatorInformation is System.lineSeparator() — so headless builds (xtext-maven-plugin, MWE2) emit platform-dependent endings that fight the repository's LF policy (.gitattributes '* text=auto eol=lf', dsldevkit#1314) and rewrite generated files on other platforms. Bind LfLineSeparatorInformation ('\n') in every DDK language runtime module (Check, CheckCfg, Scope, Export, Format, Valid, Expression) so generation is deterministic for all current and future generators of these languages at the pipeline's actual enforcement point. In the IDE the UI modules' preference/sensing provider still takes precedence, so workspaces keep converging to the checked-out form. Trace-aware JvmModel output is unaffected (its appendable is LF by construction and the harmonizer deliberately skips traced content). Completes the direction of dsldevkit#1331/dsldevkit#1413 at the root; tracked by dsldevkit#1345. Assisted by Claude
Three layers, none of which existed before: - LineEndingDeterminismTest: drives the real headless write path (JavaIoFileSystemAccess + LineSeparatorHarmonizer) with the LF binding and, as a control, with a '\r\n' binding — proving the post-processor follows the bound separator (the mechanism that made output platform-dependent) and that the LF binding normalizes CRLF, CR and LF alike. - CheckLineSeparatorBindingTest: pins the Guice module-convention wiring by resolving ILineSeparatorInformation from the Check runtime injector; the other six language modules declare the identical binding method. - AbstractCheckGenerationTestCase now asserts no generated file contains CR, upgrading every existing Check generation test into an emission regression guard; LfPrintWriterTest covers the raw-IO report writer's terminator. Assisted by Claude
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.
Problem
Generated-file line endings are platform-dependent: Xtext's default
ILineSeparatorInformationreturnsSystem.getProperty("line.separator"), so any headless generation on Windows (MWE2 workflows, standalone builders, tests, analysis reports) emits CRLF — while the committed artifacts are LF. Every such run on Windows produces whole-file line-ending diffs: git churn, spurious rebuilds, and noisy PRs.Fix
Make LF the deterministic separator for all machine-owned output:
LfLineSeparatorInformation(new,com.avaloq.tools.ddk.xtext.generator, exported): returns"\n". Bound viabindILineSeparatorInformation()in the runtime module of all seven DDK languages (Check, CheckCfg, Export, Expression, Format, Scope, Valid). Xtext'sIWhitespaceInformationProvider.Defaultinjects exactly this type and feeds it toLineSeparatorHarmonizer— the post-processor that owns the final bytes of everyIFileSystemAccesswrite — so all headless generation becomes LF. In the IDE, the UI module's preference-based whitespace provider takes precedence, so workspace behavior is unchanged.ModelInference.mwe2,TypeModel.mwe2):lineDelimiter = "\n"on theEcoreGeneratorcomponents (complements the earliercodeConfigLF change for the Xtext language workflows).KeywordAnalysisHelper: the diagnostic/report writers use anLfPrintWriter(aPrintWriterwhoseprintln()terminates with\n) instead of platform-terminatedprintln.Tests
CheckLineSeparatorBindingTestpins the Guice convention wiring (runtime injector resolvesILineSeparatorInformationto the LF binding — the identical binding method used by all seven modules).AbstractCheckGenerationTestCasenow asserts every generated file is CR-free, so all existing generation tests enforce determinism on every platform.LfPrintWriterTest+LineEndingDeterminismTestcover the report writers and end-to-end determinism in the generator bundle.Verification
ddk-parent:mvn -T 3C clean verify checkstyle:check pmd:check pmd:cpd-check spotbugs:check→ BUILD SUCCESS, 363 tests / 0 failures / 0 errors (includes the four new LF tests), all static analysis clean.IWhitespaceInformationProvider.DefaultinjectsILineSeparatorInformationandLineSeparatorHarmonizerapplies it to everyIFileSystemAccesswrite; the default being replaced isSystem.getProperty("line.separator").🤖 Generated with Claude Code