Skip to content

Commit ed919d3

Browse files
ro0grRuslan Hrabovyistevearc
authored
fix(prettierd): respect prettier config field in the "package.json" (#564)
* fix: make `prettierd` respect the `prettier` config in the "package.json" * add type annotations for `read_json` Co-authored-by: Steven Arcangeli <[email protected]> * fixup filename * use `json` module for json decode * refactor `read_json(` to respect syntax errors ...and throw an exception if a file open error occurs * fixup test module label * refactor: general touchups --------- Co-authored-by: Ruslan Hrabovyi <[email protected]> Co-authored-by: Steven Arcangeli <[email protected]>
1 parent d28ccf9 commit ed919d3

File tree

3 files changed

+206
-16
lines changed

3 files changed

+206
-16
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ tests/testfile.txt
4747
tests/fake_formatter_output
4848
scripts/nvim_doc_tools
4949
scripts/nvim-typecheck-action
50+
tmp/

lua/conform/formatters/prettierd.lua

+57-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,61 @@
11
local fs = require("conform.fs")
2+
local log = require("conform.log")
23
local util = require("conform.util")
4+
5+
local config_file_names = {
6+
-- https://prettier.io/docs/en/configuration.html
7+
".prettierrc",
8+
".prettierrc.json",
9+
".prettierrc.yml",
10+
".prettierrc.yaml",
11+
".prettierrc.json5",
12+
".prettierrc.js",
13+
".prettierrc.cjs",
14+
".prettierrc.mjs",
15+
".prettierrc.toml",
16+
"prettier.config.js",
17+
"prettier.config.cjs",
18+
"prettier.config.mjs",
19+
}
20+
21+
---@param file string
22+
---@return nil|table
23+
local function read_json(file)
24+
local f = io.open(file, "r")
25+
if not f then
26+
log.error("Unable to open file %s", file)
27+
return nil
28+
end
29+
30+
local file_content = f:read("*all") -- Read entire file contents
31+
f:close()
32+
33+
local ok, json = pcall(vim.json.decode, file_content)
34+
if not ok then
35+
log.error("Unable to parse json file %s", file)
36+
return nil
37+
end
38+
39+
return json
40+
end
41+
42+
-- TODO: share this with "lua/conform/formatters/prettier.lua"
43+
local cwd = function(self, ctx)
44+
return vim.fs.root(ctx.dirname, function(name, path)
45+
if vim.tbl_contains(config_file_names, name) then
46+
return true
47+
end
48+
49+
if name == "package.json" then
50+
local full_path = vim.fs.joinpath(path, name)
51+
local package_data = read_json(full_path)
52+
return package_data and package_data.prettier and true or false
53+
end
54+
55+
return false
56+
end)
57+
end
58+
359
---@type conform.FileFormatterConfig
460
return {
561
meta = {
@@ -12,20 +68,5 @@ return {
1268
local start_offset, end_offset = util.get_offsets_from_range(ctx.buf, ctx.range)
1369
return { "$FILENAME", "--range-start=" .. start_offset, "--range-end=" .. end_offset }
1470
end,
15-
cwd = util.root_file({
16-
-- https://prettier.io/docs/en/configuration.html
17-
".prettierrc",
18-
".prettierrc.json",
19-
".prettierrc.yml",
20-
".prettierrc.yaml",
21-
".prettierrc.json5",
22-
".prettierrc.js",
23-
".prettierrc.cjs",
24-
".prettierrc.mjs",
25-
".prettierrc.toml",
26-
"prettier.config.js",
27-
"prettier.config.cjs",
28-
"prettier.config.mjs",
29-
"package.json",
30-
}),
71+
cwd = cwd,
3172
}

tests/formatters/prettierd_spec.lua

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
require("plenary.async").tests.add_to_env()
2+
3+
local conform = require("conform")
4+
local test_util = require("tests.test_util")
5+
6+
local TMP_DIR = "./tmp/formatters/prettierd/"
7+
8+
describe("formatters/prettierd", function()
9+
before_each(function()
10+
vim.fn.mkdir(TMP_DIR, "p")
11+
end)
12+
13+
after_each(function()
14+
test_util.reset_editor()
15+
16+
vim.fn.delete(TMP_DIR, "rf")
17+
end)
18+
19+
describe("cwd", function()
20+
it("has no marker", function()
21+
vim.fn.writefile({ "{}" }, vim.fs.joinpath(TMP_DIR, "package.json"))
22+
local jsfile = vim.fs.joinpath(TMP_DIR, "some.js")
23+
vim.fn.writefile({ "" }, jsfile)
24+
25+
vim.cmd("e " .. jsfile)
26+
27+
local info = conform.get_formatter_info("prettierd")
28+
29+
assert.equal(nil, info.cwd)
30+
end)
31+
32+
describe("config file", function()
33+
it("recognizes prettier config file", function()
34+
vim.fn.writefile({ "" }, vim.fs.joinpath(TMP_DIR, ".prettierrc"))
35+
local jsfile = vim.fs.joinpath(TMP_DIR, "some.js")
36+
vim.fn.writefile({ "" }, jsfile)
37+
38+
vim.cmd("e " .. jsfile)
39+
40+
local info = conform.get_formatter_info("prettierd")
41+
42+
assert.equal(vim.fn.fnamemodify(jsfile, ":p:h"), info.cwd)
43+
end)
44+
45+
it("looks up recursively", function()
46+
vim.fn.writefile({ "" }, vim.fs.joinpath(TMP_DIR, ".prettierrc"))
47+
48+
local nested_dir = vim.fs.joinpath(TMP_DIR, "nested")
49+
vim.fn.mkdir(nested_dir, "p")
50+
vim.fn.writefile({ "{}" }, vim.fs.joinpath(nested_dir, "package.json"))
51+
52+
local jsfile = vim.fs.joinpath(nested_dir, "some.js")
53+
vim.fn.writefile({ "" }, jsfile)
54+
55+
vim.cmd("e " .. jsfile)
56+
57+
local info = conform.get_formatter_info("prettierd")
58+
59+
assert.equal(vim.fn.fnamemodify(TMP_DIR, ":p:h"), info.cwd)
60+
end)
61+
end)
62+
63+
describe("package.json", function()
64+
it("handles syntax error", function()
65+
vim.fn.writefile({ "plain text" }, vim.fs.joinpath(TMP_DIR, "package.json"))
66+
local jsfile = vim.fs.joinpath(TMP_DIR, "some.js")
67+
vim.fn.writefile({ "" }, jsfile)
68+
69+
vim.cmd("e " .. jsfile)
70+
71+
local log = {}
72+
require("conform.log").set_handler(function(text)
73+
table.insert(log, text)
74+
end)
75+
76+
local info = conform.get_formatter_info("prettierd")
77+
78+
assert.equal(nil, info.cwd)
79+
80+
assert.is_true(#log == 1)
81+
82+
assert.no_nil(string.find(log[1], "[ERROR] Unable to parse json file", 1, true))
83+
end)
84+
85+
it("recognizes prettier field", function()
86+
vim.fn.writefile({ '{"prettier": {}}' }, vim.fs.joinpath(TMP_DIR, "package.json"))
87+
local jsfile = vim.fs.joinpath(TMP_DIR, "some.js")
88+
vim.fn.writefile({ "" }, jsfile)
89+
90+
vim.cmd("e " .. jsfile)
91+
92+
local info = conform.get_formatter_info("prettierd")
93+
94+
assert.equal(vim.fn.fnamemodify(jsfile, ":p:h"), info.cwd)
95+
end)
96+
97+
-- test it explicitly just for a future traveler's clarity
98+
it("ignores prettier dependency", function()
99+
vim.fn.writefile(
100+
{ '{"dependencies": {"prettier": "1.1.1"}, "devDependencies": {"prettier": "1.1.1"}}' },
101+
vim.fs.joinpath(TMP_DIR, "package.json")
102+
)
103+
local jsfile = vim.fs.joinpath(TMP_DIR, "some.js")
104+
vim.fn.writefile({ "" }, jsfile)
105+
106+
vim.cmd("e " .. jsfile)
107+
108+
local info = conform.get_formatter_info("prettierd")
109+
110+
assert.equal(nil, info.cwd)
111+
end)
112+
113+
it("looks up recursively", function()
114+
vim.fn.writefile({ '{"prettier": {}}' }, vim.fs.joinpath(TMP_DIR, "package.json"))
115+
116+
local nested_dir = vim.fs.joinpath(TMP_DIR, "nested")
117+
vim.fn.mkdir(nested_dir, "p")
118+
vim.fn.writefile({ "{}" }, vim.fs.joinpath(nested_dir, "package.json"))
119+
120+
local jsfile = vim.fs.joinpath(nested_dir, "some.js")
121+
vim.fn.writefile({ "" }, jsfile)
122+
123+
vim.cmd("e " .. jsfile)
124+
125+
local info = conform.get_formatter_info("prettierd")
126+
127+
assert.equal(vim.fn.fnamemodify(TMP_DIR, ":p:h"), info.cwd)
128+
end)
129+
end)
130+
131+
it("stops on the first found marker", function()
132+
vim.fn.writefile({ '{"prettier": {}}' }, vim.fs.joinpath(TMP_DIR, "package.json"))
133+
134+
local nested_dir = vim.fs.joinpath(TMP_DIR, "nested")
135+
vim.fn.mkdir(nested_dir, "p")
136+
vim.fn.writefile({ '{"prettier": {}}' }, vim.fs.joinpath(nested_dir, "package.json"))
137+
138+
local jsfile = vim.fs.joinpath(nested_dir, "some.js")
139+
vim.fn.writefile({ "" }, jsfile)
140+
141+
vim.cmd("e " .. jsfile)
142+
143+
local info = conform.get_formatter_info("prettierd")
144+
145+
assert.equal(vim.fn.fnamemodify(jsfile, ":p:h"), info.cwd)
146+
end)
147+
end)
148+
end)

0 commit comments

Comments
 (0)