Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/append-separators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tanstack/create": patch
---

Keep appended add-on files on separate lines when existing content has no final newline, in both Node and edge generation.
9 changes: 8 additions & 1 deletion packages/create/src/edge-template-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,14 @@ export function createTemplateFile(environment: Environment, options: Options) {
}

if (append) {
await environment.appendFile(joinPaths(options.targetDir, target), content)
const targetPath = joinPaths(options.targetDir, target)
if (content && !/^[\r\n]/.test(content) && environment.exists(targetPath)) {
const existing = await environment.readFile(targetPath)
if (existing && !/[\r\n]$/.test(existing)) {
content = `\n${content}`
}
}
await environment.appendFile(targetPath, content)
} else {
await environment.writeFile(joinPaths(options.targetDir, target), content)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
mcp-todos.json
mcp-todos.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ VITE_SENTRY_ORG=
VITE_SENTRY_PROJECT=

# Your Sentry authentication token (from your Sentry account)
SENTRY_AUTH_TOKEN=
SENTRY_AUTH_TOKEN=
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Strapi configuration
VITE_STRAPI_URL="http://localhost:1337"
VITE_STRAPI_URL="http://localhost:1337"
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Strapi configuration
VITE_STRAPI_URL="http://localhost:1337/api"
VITE_STRAPI_URL="http://localhost:1337/api"
9 changes: 8 additions & 1 deletion packages/create/src/template-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,14 @@ export function createTemplateFile(environment: Environment, options: Options) {
}

if (append) {
await environment.appendFile(resolve(options.targetDir, target), content)
const targetPath = resolve(options.targetDir, target)
if (content && !/^[\r\n]/.test(content) && environment.exists(targetPath)) {
const existing = await environment.readFile(targetPath)
if (existing && !/[\r\n]$/.test(existing)) {
content = `\n${content}`
}
}
await environment.appendFile(targetPath, content)
} else {
await environment.writeFile(resolve(options.targetDir, target), content)
}
Expand Down
59 changes: 59 additions & 0 deletions packages/create/tests/append-separators.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { mkdtemp, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'

import { createDefaultEnvironment, createMemoryEnvironment } from '../src/environment.js'
import { createMemoryEnvironment as createEdgeMemoryEnvironment } from '../src/edge-environment.js'
import { createTemplateFile } from '../src/template-file.js'
import { createTemplateFile as createEdgeTemplateFile } from '../src/edge-template-file.js'
import type { Options } from '../src/types.js'

const cases = [
{ name: 'missing target', before: undefined, incoming: 'next\n', expected: 'next\n' },
{ name: 'empty target', before: '', incoming: 'next\n', expected: 'next\n' },
{ name: 'missing separator', before: '*.local', incoming: 'mcp-todos.json\n', expected: '*.local\nmcp-todos.json\n' },
{ name: 'existing trailing newline', before: 'first\n', incoming: 'next', expected: 'first\nnext' },
{ name: 'incoming leading newline', before: 'first', incoming: '\nnext', expected: 'first\nnext' },
{ name: 'intentional blank line', before: 'first\n', incoming: '\nnext', expected: 'first\n\nnext' },
{ name: 'empty append', before: 'first', incoming: '', expected: 'first' },
{ name: 'existing CRLF', before: 'first\r\n', incoming: 'next', expected: 'first\r\nnext' },
{ name: 'incoming CRLF', before: 'first', incoming: '\r\nnext', expected: 'first\r\nnext' },
]

for (const kind of ['disk', 'node-memory', 'edge-memory'] as const) {
describe(`${kind} append templates`, () => {
it.each(cases)('$name', async ({ before, incoming, expected }) => {
const targetDir = await mkdtemp(join(tmpdir(), 'tanstack-append-'))
const environment = kind === 'disk'
? createDefaultEnvironment()
: kind === 'node-memory'
? createMemoryEnvironment().environment
: createEdgeMemoryEnvironment().environment
const options: Options = {
projectName: 'test', targetDir,
framework: {
id: 'test', name: 'Test', description: '', version: '1',
basePackageJSON: {}, optionalPackages: {}, supportedModes: {},
getFiles: async () => [], getFileContents: async () => '',
getDeletedFiles: async () => [], getAddOns: () => [],
},
chosenAddOns: [], addOnOptions: {}, packageManager: 'npm',
typescript: true, tailwind: false, mode: 'file-router',
git: false, intent: false,
}
const templateFile = kind === 'edge-memory'
? createEdgeTemplateFile(environment, options)
: createTemplateFile(environment, options)
try {
environment.startRun()
if (before !== undefined) await templateFile('_dot_gitignore', before)
await templateFile('_dot_gitignore.append', incoming)
expect(await environment.readFile(join(targetDir, '.gitignore'))).toBe(expected)
} finally {
environment.finishRun()
await rm(targetDir, { recursive: true, force: true })
}
})
})
}
Loading