Skip to content

feat: support comments in vscode settings #5436

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Feb 9, 2023
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
63 changes: 63 additions & 0 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
"ci-info": "^3.0.0",
"clean-deep": "^3.0.2",
"commander": "^9.2.0",
"comment-json": "^4.2.3",
"concordance": "^5.0.0",
"configstore": "^5.0.0",
"content-type": "^1.0.4",
Expand Down
13 changes: 7 additions & 6 deletions src/recipes/vscode/settings.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { mkdir, readFile, stat, writeFile } from 'fs/promises'
import { dirname, relative } from 'path'

// eslint-disable-next-line import/no-namespace
import * as JSONC from 'comment-json'
import unixify from 'unixify'

export const applySettings = (existingSettings, { denoBinary, edgeFunctionsPath, repositoryRoot }) => {
const relativeEdgeFunctionsPath = unixify(relative(repositoryRoot, edgeFunctionsPath))
const settings = {
...existingSettings,
const settings = JSONC.assign(existingSettings, {
'deno.enable': true,
'deno.enablePaths': existingSettings['deno.enablePaths'] || [],
'deno.unstable': true,
'deno.importMap': '.netlify/edge-functions-import-map.json',
}
})

// If the Edge Functions path isn't already in `deno.enabledPaths`, let's add
// it.
Expand All @@ -38,11 +39,11 @@ export const getSettings = async (settingsPath) => {
throw new Error(`${settingsPath} is not a valid file.`)
}

const file = await readFile(settingsPath)
const file = await readFile(settingsPath, 'utf8')

return {
fileExists: true,
settings: JSON.parse(file),
settings: JSONC.parse(file),
}
} catch (error) {
if (error.code !== 'ENOENT') {
Expand All @@ -57,7 +58,7 @@ export const getSettings = async (settingsPath) => {
}

export const writeSettings = async ({ settings, settingsPath }) => {
const serializedSettings = JSON.stringify(settings, null, 2)
const serializedSettings = JSONC.stringify(settings, null, 2)

await mkdir(dirname(settingsPath), { recursive: true })
await writeFile(settingsPath, serializedSettings)
Expand Down
45 changes: 44 additions & 1 deletion tests/integration/640.command.recipes.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ const { readFile } = require('fs/promises')
const { resolve } = require('path')

const test = require('ava')
const { parse } = require('comment-json')
const execa = require('execa')

const callCli = require('./utils/call-cli.cjs')
const cliPath = require('./utils/cli-path.cjs')
const { CONFIRM, answerWithValue, handleQuestions } = require('./utils/handle-questions.cjs')
const { CONFIRM, NO, answerWithValue, handleQuestions } = require('./utils/handle-questions.cjs')
const { withSiteBuilder } = require('./utils/site-builder.cjs')
const { normalize } = require('./utils/snapshots.cjs')

Expand Down Expand Up @@ -96,3 +97,45 @@ test('Does not generate a new VS Code settings file if the user does not confirm
t.is(error.code, 'ENOENT')
})
})

test('Handles JSON with comments', async (t) => {
await withSiteBuilder('repo', async (builder) => {
const comment = '// sets value for someSetting'
await builder
.withContentFile({
path: '.vscode/settings.json',
content: `{
"deno.enablePaths":["/some/path"],
"someSetting":"value" ${comment}
}`,
})
.buildAsync()

const childProcess = execa(cliPath, ['recipes', 'vscode'], {
cwd: builder.directory,
})
const settingsPath = resolve(builder.directory, '.vscode', 'settings.json')

handleQuestions(childProcess, [
{
question: `There is a VS Code settings file at ${settingsPath}. Can we update it?`,
answer: answerWithValue(CONFIRM),
},
{
question: 'The Deno VS Code extension is recommended. Would you like to install it now?',
answer: answerWithValue(NO),
},
])
Comment on lines +124 to +128
Copy link
Contributor Author

@tinfoil-knight tinfoil-knight Feb 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danez Note here:

The Deno VS Code extension is recommended. Would you like to install it now? prompt is there on my local system but it seems like this question is not asked during the CI run. The test just ends up stuck on local env & didn't run before adding the question.

I've added the prompt for this test but this issue is there for other tests too. Should I add the extra prompt for other tests too (wherever applicable) in a separate PR?


await childProcess

const settingsText = await readFile(`${builder.directory}/.vscode/settings.json`, { encoding: 'utf8' })
t.true(settingsText.includes(comment))

const settings = parse(settingsText, null, true)
t.is(settings.someSetting, 'value')
t.is(settings['deno.enable'], true)
t.is(settings['deno.importMap'], '.netlify/edge-functions-import-map.json')
t.deepEqual([...settings['deno.enablePaths']], ['/some/path', 'netlify/edge-functions'])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spreading the array here since that converts it from the CommentArray type to a native JS array for comparison.

})
})
2 changes: 2 additions & 0 deletions tests/integration/utils/handle-questions.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ const answerWithValue = (value) => `${value}${CONFIRM}`

const CONFIRM = '\n'
const DOWN = '\u001B[B'
const NO = 'n'

module.exports = {
handleQuestions,
answerWithValue,
CONFIRM,
DOWN,
NO,
}