diff --git a/extensions/oni-plugin-prettier/index.js b/extensions/oni-plugin-prettier/index.js index 7836cbdf7e..45d9a72113 100644 --- a/extensions/oni-plugin-prettier/index.js +++ b/extensions/oni-plugin-prettier/index.js @@ -1,5 +1,5 @@ const path = require("path") -const prettier = require("prettier") +const { requireLocalPkg } = require("./requirePackage") // Helper functions const compose = (...fns) => argument => fns.reduceRight((arg, fn) => fn(arg), argument) @@ -19,17 +19,25 @@ const isCompatible = (allowedFiletypes, defaultFiletypes) => filePath => { return filetypes.includes(extension) } -const getSupportedLanguages = async () => { +const getSupportedLanguages = async prettier => { const info = await prettier.getSupportInfo() return flatten(info.languages.map(lang => lang.extensions)) } const activate = async Oni => { + // Prettier Module to Use - local or oni-bundled + let PrettierModule = requireLocalPkg(process.cwd(), "prettier") + const config = Oni.configuration.getValue("oni.plugins.prettier") const prettierItem = Oni.statusBar.createItem(0, "oni.plugins.prettier") + // Update Prettier Module to use when oni dir changes + Oni.workspace.onDirectoryChanged.subscribe(dir => { + PrettierModule = requireLocalPkg(dir, "prettier") + }) + const applyPrettierWithState = applyPrettier() - const defaultFiletypes = await getSupportedLanguages() + const defaultFiletypes = await getSupportedLanguages(PrettierModule) const callback = async () => { const isNormalMode = Oni.editors.activeEditor.mode === "normal" @@ -48,7 +56,7 @@ const activate = async Oni => { throw new Error(`No buffer path passed for prettier to check for a Prettierrc`) } try { - return await prettier.resolveConfig(bufferPath) + return await PrettierModule.resolveConfig(bufferPath) } catch (e) { throw new Error(`Error parsing config file, ${e}`) } @@ -95,7 +103,7 @@ const activate = async Oni => { const prettierConfig = eitherOr(prettierrc, config.settings) // Pass in the file path so prettier can infer the correct parser to use - const { formatted, cursorOffset } = prettier.formatWithCursor( + const { formatted, cursorOffset } = PrettierModule.formatWithCursor( join(arrayOfLines), Object.assign({ filepath: activeBuffer.filePath }, prettierConfig, { cursorOffset: activeBuffer.cursorOffset, @@ -158,7 +166,6 @@ function createPrettierComponent(Oni, onClick) { paddingLeft: "8px", paddingRight: "8px", color: "white", - backgroundColor: foreground, } const prettierIcon = (type = "magic") => diff --git a/extensions/oni-plugin-prettier/package.json b/extensions/oni-plugin-prettier/package.json index a4dfce72e7..e9d703d0d5 100644 --- a/extensions/oni-plugin-prettier/package.json +++ b/extensions/oni-plugin-prettier/package.json @@ -12,7 +12,9 @@ ] }, "dependencies": { - "prettier": "^1.11.1" + "prettier": "^1.13.6", + "read-pkg-up": "^4.0.0", + "resolve": "^1.8.1" }, "devDependencies": {} } diff --git a/extensions/oni-plugin-prettier/requirePackage.js b/extensions/oni-plugin-prettier/requirePackage.js new file mode 100644 index 0000000000..5ef61f9374 --- /dev/null +++ b/extensions/oni-plugin-prettier/requirePackage.js @@ -0,0 +1,52 @@ +const path = require("path") +const resolve = require("resolve") +const readPkgUp = require("read-pkg-up") + +// CREDIT: Shamelessly *borrowed* from prettier-vscode + +/** + * Recursively search for a package.json upwards containing given package + * as a dependency or devDependency. + * @param {string} fspath file system path to start searching from + * @param {string} pkgName package's name to search for + * @returns {string} resolved path to prettier + */ +function findPkg(fspath = process.cwd(), pkgName) { + const res = readPkgUp.sync({ cwd: fspath, normalize: false }) + const { root } = path.parse(fspath) + if ( + res.pkg && + ((res.pkg.dependencies && res.pkg.dependencies[pkgName]) || + (res.pkg.devDependencies && res.pkg.devDependencies[pkgName])) + ) { + return resolve.sync(pkgName, { basedir: res.path }) + } else if (res.path) { + const parent = path.resolve(path.dirname(res.path), "..") + if (parent !== root) { + return findPkg(parent, pkgName) + } + } + return +} + +/** + * Require package explicitely installed relative to given path. + * Fallback to bundled one if no pacakge was found bottom up. + * @param {string} fspath file system path starting point to resolve package + * @param {string} pkgName package's name to require + * @returns module + */ +function requireLocalPkg(fspath, pkgName) { + const modulePath = findPkg(fspath, pkgName) + if (modulePath) { + try { + return require(modulePath) + } catch (e) { + console.warn(`Failed to load ${pkgName} from ${modulePath}. Using bundled`) + } + } + + return require(pkgName) +} + +module.exports = { requireLocalPkg }