Flip files from CRLF to LF - #64046
Conversation
There was a problem hiding this comment.
Pull request overview
Converts repository text files from CRLF to LF and configures Git to retain LF endings.
Changes:
- Adds repository-wide LF normalization with fixture exclusions.
- Converts scripts, API sources, tests, and documentation to LF.
- Regenerates bundled libraries and affected call-hierarchy baselines.
Reviewed changes
Copilot reviewed 10 out of 293 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
.gitattributes |
Configures LF normalization and exclusions. |
.github/pull_request_template.md |
Converts line endings. |
README.md |
Converts line endings. |
tools/scripts/link-hooks.mjs |
Converts line endings. |
tools/scripts/tsc/generate.ts |
Converts line endings. |
tsc/internal/lsp/lsproto/_generate/fetchModel.mts |
Converts line endings. |
tsc/internal/format/README.md |
Converts line endings. |
tsc/internal/bundled/README.md |
Converts line endings. |
tsc/internal/bundled/generate.go |
Changes bundled-lib header validation. |
tsc/internal/bundled/libs/lib.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.decorators.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.decorators.legacy.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es5.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es6.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2015.collection.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2015.core.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2015.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2015.generator.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2015.iterable.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2015.promise.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2015.proxy.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2015.reflect.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2015.symbol.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2015.symbol.wellknown.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2016.array.include.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2016.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2016.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2016.intl.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2017.arraybuffer.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2017.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2017.date.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2017.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2017.intl.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2017.object.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2017.sharedmemory.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2017.string.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2017.typedarrays.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2018.asyncgenerator.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2018.asynciterable.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2018.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2018.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2018.intl.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2018.promise.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2018.regexp.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2019.array.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2019.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2019.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2019.intl.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2019.object.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2019.string.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2019.symbol.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2020.bigint.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2020.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2020.date.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2020.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2020.intl.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2020.number.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2020.promise.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2020.sharedmemory.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2020.string.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2020.symbol.wellknown.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2021.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2021.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2021.intl.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2021.promise.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2021.string.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2021.weakref.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2022.array.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2022.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2022.error.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2022.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2022.intl.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2022.object.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2022.regexp.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2022.string.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2023.array.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2023.collection.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2023.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2023.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2023.intl.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2024.arraybuffer.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2024.collection.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2024.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2024.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2024.object.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2024.promise.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2024.regexp.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2024.sharedmemory.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2024.string.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2025.collection.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2025.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2025.float16.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2025.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2025.intl.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2025.iterator.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2025.promise.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.es2025.regexp.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.array.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.collection.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.date.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.decorators.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.disposable.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.error.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.full.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.intl.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.sharedmemory.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.temporal.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.esnext.typedarrays.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.scripthost.d.ts |
Converts LF and removes a blank line. |
tsc/internal/bundled/libs/lib.webworker.importscripts.d.ts |
Converts LF and removes a blank line. |
tsc/testdata/baselines/reference/fourslash/callHierarchy/callHierarchyInPropDeclarationOfExportedDefaultClass1.callHierarchy.txt |
Updates shifted lib line numbers. |
tsc/testdata/baselines/reference/fourslash/callHierarchy/callHierarchyIncomingCallsNoCrashArrayPush.callHierarchy.txt |
Updates shifted lib line numbers. |
tsc/testdata/baselines/reference/fourslash/callHierarchy/callHierarchyIncomingCallsObjectLiteralMethodInExpressionComputedProperty.callHierarchy.txt |
Updates shifted lib line numbers. |
tsc/testdata/baselines/reference/fourslash/callHierarchy/callHierarchyIncomingCallsObjectLiteralMethodInIdentifierComputedProperty.callHierarchy.txt |
Updates shifted lib line numbers. |
tsc/testdata/baselines/reference/fourslash/callHierarchy/callHierarchyIncomingCallsObjectLiteralMethodInStringLiteralComputedProperty.callHierarchy.txt |
Updates shifted lib line numbers. |
packages/vscode-typescript/test/index.test.ts |
Converts line endings. |
packages/vscode-typescript/test/contentMapperContributions.test.ts |
Converts line endings. |
packages/vscode-typescript/src/workspaceSymbolMiddleware.ts |
Converts line endings. |
packages/vscode-typescript/src/vscode.proposed.multiDocumentHighlightProvider.d.ts |
Converts line endings. |
packages/vscode-typescript/src/vscode.proposed.editorHoverVerbosityLevel.d.ts |
Converts line endings. |
packages/vscode-typescript/src/tsdkPackage.ts |
Converts line endings. |
packages/vscode-typescript/src/statusBar.ts |
Converts line endings. |
packages/vscode-typescript/src/managedFileContext.ts |
Converts line endings. |
packages/vscode-typescript/src/languageFeatures/util/dependentRegistration.ts |
Converts line endings. |
packages/vscode-typescript/src/languageFeatures/hover.ts |
Converts line endings. |
packages/vscode-typescript/src/languageFeatures/documentHighlight.ts |
Converts line endings. |
packages/vscode-typescript/src/experimentationService.ts |
Converts line endings. |
packages/typescript/test/wtf8.test.ts |
Converts line endings. |
packages/typescript/test/version.test.ts |
Converts line endings. |
packages/typescript/test/types.d.ts |
Converts line endings. |
packages/typescript/test/api.bench.ts |
Converts line endings. |
packages/typescript/src/internal/utils.ts |
Converts line endings. |
packages/typescript/src/ast/index.ts |
Converts line endings. |
packages/typescript/src/api/options.ts |
Converts line endings. |
packages/typescript/src/api/node/wtf8.ts |
Converts line endings. |
packages/typescript/src/api/node/protocol.ts |
Converts line endings. |
packages/typescript/src/enums/typePredicateKind.ts |
Converts line endings. |
packages/typescript/src/enums/typePredicateKind.enum.ts |
Converts line endings. |
packages/typescript/src/enums/typeFormatFlags.ts |
Converts line endings. |
packages/typescript/src/enums/typeFormatFlags.enum.ts |
Converts line endings. |
packages/typescript/src/enums/tokenFlags.ts |
Converts line endings. |
packages/typescript/src/enums/tokenFlags.enum.ts |
Converts line endings. |
packages/typescript/src/enums/spanMapKind.ts |
Converts line endings. |
packages/typescript/src/enums/spanMapKind.enum.ts |
Converts line endings. |
packages/typescript/src/enums/spanMapFidelity.ts |
Converts line endings. |
packages/typescript/src/enums/spanMapFidelity.enum.ts |
Converts line endings. |
packages/typescript/src/enums/spanMapFeature.ts |
Converts line endings. |
packages/typescript/src/enums/spanMapFeature.enum.ts |
Converts line endings. |
packages/typescript/src/enums/signatureKind.ts |
Converts line endings. |
packages/typescript/src/enums/signatureKind.enum.ts |
Converts line endings. |
packages/typescript/src/enums/signatureFlags.ts |
Converts line endings. |
packages/typescript/src/enums/signatureFlags.enum.ts |
Converts line endings. |
packages/typescript/src/enums/scriptTarget.ts |
Converts line endings. |
packages/typescript/src/enums/scriptTarget.enum.ts |
Converts line endings. |
packages/typescript/src/enums/scriptKind.ts |
Converts line endings. |
packages/typescript/src/enums/scriptKind.enum.ts |
Converts line endings. |
packages/typescript/src/enums/regularExpressionFlags.ts |
Converts line endings. |
packages/typescript/src/enums/regularExpressionFlags.enum.ts |
Converts line endings. |
packages/typescript/src/enums/outerExpressionKinds.ts |
Converts line endings. |
packages/typescript/src/enums/outerExpressionKinds.enum.ts |
Converts line endings. |
packages/typescript/src/enums/objectFlags.enum.ts |
Converts line endings. |
packages/typescript/src/enums/nodeFlags.enum.ts |
Converts line endings. |
packages/typescript/src/enums/nodeBuilderFlags.enum.ts |
Converts line endings. |
packages/typescript/src/enums/newLineKind.ts |
Converts line endings. |
packages/typescript/src/enums/newLineKind.enum.ts |
Converts line endings. |
packages/typescript/src/enums/moduleResolutionKind.ts |
Converts line endings. |
packages/typescript/src/enums/moduleResolutionKind.enum.ts |
Converts line endings. |
packages/typescript/src/enums/moduleKind.ts |
Converts line endings. |
packages/typescript/src/enums/moduleKind.enum.ts |
Converts line endings. |
packages/typescript/src/enums/moduleDetectionKind.ts |
Converts line endings. |
packages/typescript/src/enums/moduleDetectionKind.enum.ts |
Converts line endings. |
packages/typescript/src/enums/modifierFlags.enum.ts |
Converts line endings. |
packages/typescript/src/enums/languageVariant.ts |
Converts line endings. |
packages/typescript/src/enums/languageVariant.enum.ts |
Converts line endings. |
packages/typescript/src/enums/jsxEmit.ts |
Converts line endings. |
packages/typescript/src/enums/jsxEmit.enum.ts |
Converts line endings. |
packages/typescript/src/enums/internalSymbolName.ts |
Converts line endings. |
packages/typescript/src/enums/internalSymbolName.enum.ts |
Converts line endings. |
packages/typescript/src/enums/emitOnly.ts |
Converts line endings. |
packages/typescript/src/enums/emitOnly.enum.ts |
Converts line endings. |
packages/typescript/src/enums/elementFlags.ts |
Converts line endings. |
packages/typescript/src/enums/elementFlags.enum.ts |
Converts line endings. |
packages/typescript/src/enums/diagnosticDirectivePolicy.ts |
Converts line endings. |
packages/typescript/src/enums/diagnosticDirectivePolicy.enum.ts |
Converts line endings. |
packages/typescript/src/enums/diagnosticCategory.ts |
Converts line endings. |
packages/typescript/src/enums/diagnosticCategory.enum.ts |
Converts line endings. |
packages/typescript/src/enums/completionItemKind.ts |
Converts line endings. |
packages/typescript/src/enums/completionItemKind.enum.ts |
Converts line endings. |
packages/typescript/src/enums/commentDirectiveType.ts |
Converts line endings. |
packages/typescript/src/enums/commentDirectiveType.enum.ts |
Converts line endings. |
packages/typescript/src/enums/checkFlags.ts |
Converts line endings. |
packages/typescript/src/enums/checkFlags.enum.ts |
Converts line endings. |
packages/typescript/lib/version.d.cts |
Converts line endings. |
packages/typescript/lib/version.cjs |
Converts line endings. |
packages/typescript/lib/tsc.js |
Converts line endings. |
packages/typescript/lib/getExePath.d.ts |
Converts line endings. |
Suppressed comments (1)
tsc/internal/bundled/generate.go:94
- This normalization removes one blank line from every bundled lib instead of only changing its line endings. That shifts all public lib source positions (as shown by the accompanying call-hierarchy baseline changes), which is an observable and unrelated content change for a line-ending-only PR. Please preserve the existing three-newline boundary after
CopyrightNotice.txt, restore the deleted blank lines in the libs, and revert the resulting baseline offsets.
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
7f952fa to
ebc567d
Compare
Wesley Wigham (weswigham)
left a comment
There was a problem hiding this comment.
Will we need any changes to local gitconfigs to make this work on windows machines or is the local .gitattributes sufficient?
|
Nope, gitattributes does it all |
78aa9a8 to
4a1d35e
Compare
4a1d35e to
48e7f26
Compare
48e7f26 to
d380fec
Compare
|
Unfortunately, I checked this, and it seems like while the gitattributes enforce files that get pulled and how the files are stored, if you make a CRLF file locally, it won't actually auto fix it for you, you'll just be operating on a file with CRLF while committing files that use LF. I'm not sure how bad that is. We'd just need to get everyone to actually adopt that VS Code setting. Otherwise it's at least checked in CI. Perhaps I need to add a hereby task which can flip the files? |
972df32 to
3f95775
Compare
3f95775 to
d93e91b
Compare
[git-generate]
node <<'NODE'
const fs = require("node:fs");
const path = ".gitattributes";
const from = `* -text
*.go text eol=lf`;
const to = `
* text=auto eol=lf
# Preserve line-ending-sensitive fixtures exactly.
tsc/testdata/** -text
# TODO: Remove this exception when this directory is converted or removed.
tsc/internal/locale/lcl/** -text`;
const text = fs.readFileSync(path, "utf8");
const index = text.indexOf(from);
if (index < 0 || text.indexOf(from, index + from.length) >= 0) {
throw new Error(`expected exactly one match in ${path}`);
}
fs.writeFileSync(path, text.slice(0, index) + to + text.slice(index + from.length));
NODE
[git-generate] git add --renormalize .
[git-generate]
node <<'NODE'
const fs = require("node:fs");
function replaceOnce(path, from, to) {
const text = fs.readFileSync(path, "utf8");
const index = text.indexOf(from);
if (index < 0 || text.indexOf(from, index + from.length) >= 0) {
throw new Error(`expected exactly one match in ${path}`);
}
fs.writeFileSync(path, text.slice(0, index) + to + text.slice(index + from.length));
}
replaceOnce(".dprint.jsonc", '"newLineKind": "auto"', '"newLineKind": "lf"');
replaceOnce(".dprint.jsonc", '"newLineKind": "crlf"', '"newLineKind": "lf"');
const path = ".dprint.jsonc";
const text = fs.readFileSync(path, "utf8");
const pattern = /^ "tsc\/internal\/bundled\/source\/\*\*",\r?\n/gm;
const matches = text.match(pattern);
if (matches?.length !== 1) {
throw new Error(`expected exactly one obsolete exclusion in ${path}`);
}
fs.writeFileSync(path, text.replace(pattern, ""));
NODE
npx dprint fmt
[git-generate]
node <<'NODE'
const fs = require("node:fs");
function replaceOnce(path, from, to) {
const text = fs.readFileSync(path, "utf8");
const index = text.indexOf(from);
if (index < 0 || text.indexOf(from, index + from.length) >= 0) {
throw new Error(`expected exactly one match in ${path}`);
}
fs.writeFileSync(path, text.slice(0, index) + to + text.slice(index + from.length));
}
replaceOnce(
"tsc/internal/bundled/generate.go",
`\tif bytes.ContainsRune(copyright, '\\r') || !bytes.HasSuffix(copyright, []byte("\\n\\n")) {
\t\tlog.Fatalf("%s must use LF line endings and end with a blank line", copyrightNotice)
\t}
\theader := append(copyright, '\\n')`,
`\theader := append(bytes.TrimRight(copyright, "\\n"), '\\n', '\\n')`,
);
replaceOnce(
"tsc/internal/bundled/generate.go",
`\t\tif bytes.ContainsRune(content, '\\r') {
\t\t\tlog.Fatalf("%s must use LF line endings", path)
\t\t}
\t\tif !bytes.HasPrefix(content, header) {
\t\t\tlog.Fatalf("%s must start with %s followed by a blank line", path, copyrightNotice)
\t\t}
\t\tif !bytes.HasSuffix(content, []byte("\\n")) {
\t\t\tlog.Fatalf("%s must end with a newline", path)
\t\t}`,
`\t\tif !bytes.HasPrefix(content, header) {
\t\t\tlog.Fatalf("%s must start with %s", path, copyrightNotice)
\t\t}`,
);
NODE
[git-generate]
node <<'NODE'
const fs = require("node:fs");
const path = ".dprint.jsonc";
const from = ' "tsc/internal/bundled/libs/**",';
const to = ` "tsc/internal/bundled/libs/lib.dom.d.ts",
"tsc/internal/bundled/libs/lib.dom.asynciterable.d.ts",
"tsc/internal/bundled/libs/lib.dom.iterable.d.ts",
"tsc/internal/bundled/libs/lib.webworker.d.ts",
"tsc/internal/bundled/libs/lib.webworker.asynciterable.d.ts",
"tsc/internal/bundled/libs/lib.webworker.iterable.d.ts",`;
const text = fs.readFileSync(path, "utf8");
const index = text.indexOf(from);
if (index < 0 || text.indexOf(from, index + from.length) >= 0) {
throw new Error(`expected exactly one match in ${path}`);
}
fs.writeFileSync(path, text.slice(0, index) + to + text.slice(index + from.length));
NODE
npx dprint fmt
node <<'NODE'
const fs = require("node:fs");
fs.rmSync("tsc/testdata/baselines/local", { recursive: true, force: true });
NODE
npx hereby test || true
npx hereby baseline-accept
node <<'NODE'
const fs = require("node:fs");
fs.rmSync("tsc/testdata/baselines/local", { recursive: true, force: true });
NODE
[git-generate]
node <<'NODE'
const fs = require("node:fs");
const path = "Herebyfile.mjs";
const text = fs.readFileSync(path, "utf8");
const marker = `export const checkFormat = task({
name: "check:format",
description: "Checks that the repo is formatted.",
run: async () => {`;
const markerIndex = text.indexOf(marker);
if (markerIndex < 0 || text.indexOf(marker, markerIndex + marker.length) >= 0) {
throw new Error(`expected exactly one checkFormat task in ${path}`);
}
const bodyStart = markerIndex + marker.length;
const bodyEnd = text.indexOf("\n },\n});", bodyStart);
if (bodyEnd < 0) {
throw new Error(`could not find checkFormat task body in ${path}`);
}
const body = text.slice(bodyStart, bodyEnd);
if (!body.includes("dprint") || body.includes("checkLineEndings")) {
throw new Error(`unexpected checkFormat task body in ${path}`);
}
const replacement = `${marker}${body}
await checkLineEndings();
},
});
async function checkLineEndings() {
const exclusions = [
":(exclude)tsc/testdata/**",
// TODO: Remove this exclusion when this directory is converted or removed.
":(exclude)tsc/internal/locale/lcl/**",
];
const result = await x(
"git",
["grep", "--cached", "-Il", "\\r", "--", ".", ...exclusions],
{ throwOnError: false, nodeOptions: { stdio: "pipe" } },
);
if (result.exitCode === 1) {
return;
}
if (result.exitCode !== 0) {
throw new Error(\`Failed to check line endings:\\n\${result.stderr}\`);
}
throw new Error(\`Files must use LF line endings:\\n\${result.stdout}\`);
}`;
fs.writeFileSync(path, text.slice(0, markerIndex) + replacement + text.slice(bodyEnd + "\n },\n});".length));
NODE
[git-generate]
node <<'NODE'
const fs = require("node:fs");
const files = [
"tsc/testdata/tests/cases/compiler/collisionCodeGenModuleWithUnicodeNames.ts",
"tsc/testdata/tests/cases/compiler/instanceofOperator.ts",
"tsc/testdata/tests/cases/compiler/promiseTest.ts",
"tsc/testdata/tests/cases/compiler/targetTypeBaseCalls.ts",
"tsc/testdata/tests/cases/compiler/unicodeIdentifierNames.ts",
];
for (const file of files) {
const data = fs.readFileSync(file);
if (data[0] !== 0xff || data[1] !== 0xfe) {
throw new Error(`${file} does not start with a UTF-16LE BOM`);
}
const text = data.toString("utf16le", 2).replaceAll("\r\n", "\n");
fs.writeFileSync(file, text);
}
NODE
[git-generate]
node <<'NODE'
const fs = require("node:fs");
const path = ".vscode/settings.template.json";
let text = fs.readFileSync(path, "utf8");
const from = `{
"[typescript][typescriptreact][javascript][javascriptreact][json][jsonc][yaml][github-actions-workflow]":`;
const to = `{
"files.eol": "\\n",
"[typescript][typescriptreact][javascript][javascriptreact][json][jsonc][yaml][github-actions-workflow]":`;
if (!text.includes(from) || text.indexOf(from) !== text.lastIndexOf(from)) {
throw new Error(`expected exactly one insertion point in ${path}`);
}
text = text.replace(from, to);
const scoped = ` "[go][go.mod][go.sum][go.work]": {
"files.eol": "\\n",`;
const unscoped = ` "[go][go.mod][go.sum][go.work]": {`;
if (!text.includes(scoped) || text.indexOf(scoped) !== text.lastIndexOf(scoped)) {
throw new Error(`expected exactly one scoped EOL setting in ${path}`);
}
fs.writeFileSync(path, text.replace(scoped, unscoped));
NODE
[git-generate]
node <<'NODE'
const fs = require("node:fs");
fs.writeFileSync(".editorconfig", `root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[tsc/testdata/**]
end_of_line = unset
charset = unset
trim_trailing_whitespace = unset
insert_final_newline = unset
[tsc/internal/locale/lcl/**]
end_of_line = unset
charset = unset
trim_trailing_whitespace = unset
insert_final_newline = unset
`);
const path = "Herebyfile.mjs";
let text = fs.readFileSync(path, "utf8");
const formatMarker = `async function runFormat() {`;
const formatStart = text.indexOf(formatMarker);
if (formatStart < 0 || text.indexOf(formatMarker, formatStart + formatMarker.length) >= 0) {
throw new Error(`expected exactly one runFormat function in ${path}`);
}
const formatBodyStart = formatStart + formatMarker.length;
const formatBodyEnd = text.indexOf("\n}", formatBodyStart);
if (formatBodyEnd < 0) {
throw new Error(`could not find runFormat body in ${path}`);
}
const formatBody = text.slice(formatBodyStart, formatBodyEnd);
if (!formatBody.includes("dprint") || formatBody.includes("fixLineEndings")) {
throw new Error(`unexpected runFormat body in ${path}`);
}
const formatTo = `${formatMarker}${formatBody}
await fixLineEndings();
}
const lineEndingExclusions = [
":(exclude)tsc/testdata/**",
// TODO: Remove this exclusion when this directory is converted or removed.
":(exclude)tsc/internal/locale/lcl/**",
];
export const fixLineEndingsTask = task({
name: "fix:line-endings",
description: "Converts tracked files that Git expects to use LF.",
run: fixLineEndings,
});
async function fixLineEndings() {
const result = await runOutput("git", ["ls-files", "--eol", "-z", "--", ".", ...lineEndingExclusions]);
const files = [];
for (const record of result.stdout.split("\\0")) {
if (!record) {
continue;
}
const separator = record.indexOf("\\t");
assert(separator !== -1);
const eolInfo = record.slice(0, separator);
if (!/\\bw\\/(?:crlf|mixed)\\b/.test(eolInfo) || !eolInfo.includes("eol=lf")) {
continue;
}
files.push(record.slice(separator + 1));
}
await Promise.all(files.map(async file => {
const contents = await fs.promises.readFile(file);
const normalized = Buffer.from(contents.toString("latin1").replaceAll("\\r\\n", "\\n"), "latin1");
await fs.promises.writeFile(file, normalized);
}));
if (files.length) {
console.log(\`Converted \${files.length} file(s) to LF.\`);
}
}`;
text = text.slice(0, formatStart) + formatTo + text.slice(formatBodyEnd + 2);
const checkMarker = `async function checkLineEndings() {`;
const checkStart = text.indexOf(checkMarker);
if (checkStart < 0 || text.indexOf(checkMarker, checkStart + checkMarker.length) >= 0) {
throw new Error(`expected exactly one checkLineEndings function in ${path}`);
}
const exclusionsSpread = "...exclusions";
const exclusionsIndex = text.indexOf(exclusionsSpread, checkStart);
if (exclusionsIndex < 0 || text.indexOf(exclusionsSpread, exclusionsIndex + exclusionsSpread.length) >= 0) {
throw new Error(`expected exactly one line-ending exclusion reference in ${path}`);
}
text = text.slice(0, exclusionsIndex)
+ "...lineEndingExclusions"
+ text.slice(exclusionsIndex + exclusionsSpread.length);
fs.writeFileSync(path, text);
NODE
d93e91b to
6ab852a
Compare
Historically, all files in the TS repo were CRLF, including our actual main code in
src. This is extra annoying now-a-days where agents, tools, etc, tend to screw up CRLF,git diff --checkhates it, etc. But changing that is hard.But, now, we're in Go, and I made sure the repo always enforced LF for
.gofiles, which means the only remaining CRLF source we have are the public API code (new) and then misc files like scripts, lib.d.ts.I think we can safely switch over.
A follow up can add a
.git-blame-ignoreentry, which does appear to work in my testing.After this, the only files with CRLF are:
tsc/testdata/**- input test files, but definitely output test files as we default to CRLFtsc/internal/locale/lcl/**- dead in Redo localization for onboarding #63987, though it's possible that the loc team will break this in the files they push to us; it won't matter too much..gitattributeswill probably be enough to keep this working.