From f165c1dd63a2a76309f5fc77e92dd98e5a38fad1 Mon Sep 17 00:00:00 2001 From: Jamie Mason Date: Sun, 19 Sep 2021 23:15:44 +0100 Subject: [PATCH] refactor(sources): resolve globs and files using fp-ts --- jest.config.js | 8 +- package.json | 1 + src/commands/fix-mismatches.ts | 4 +- src/commands/lib/get-wrappers.ts | 83 ------------------- .../lib/get-wrappers/get-file-paths.ts | 43 ++++++++++ .../get-patterns/get-lerna-patterns.ts | 20 +++++ .../get-patterns/get-pnpm-patterns.ts | 28 +++++++ .../get-patterns/get-yarn-patterns.ts | 30 +++++++ .../lib/get-wrappers/get-patterns/index.ts | 50 +++++++++++ .../lib/get-wrappers/get-patterns/props.ts | 19 +++++ .../get-patterns/read-json-safe.ts | 26 ++++++ .../get-patterns/read-yaml-safe.ts | 7 ++ .../{ => get-wrappers}/get-wrappers.spec.ts | 18 ++-- src/commands/lib/get-wrappers/index.ts | 46 ++++++++++ src/commands/lib/get-wrappers/readonly.ts | 6 ++ src/commands/lib/get-wrappers/tap.ts | 14 ++++ src/commands/lib/get-wrappers/try-catch.ts | 9 ++ src/commands/lib/write-if-changed.ts | 3 +- src/constants.ts | 2 + yarn.lock | 5 ++ 20 files changed, 326 insertions(+), 96 deletions(-) delete mode 100644 src/commands/lib/get-wrappers.ts create mode 100644 src/commands/lib/get-wrappers/get-file-paths.ts create mode 100644 src/commands/lib/get-wrappers/get-patterns/get-lerna-patterns.ts create mode 100644 src/commands/lib/get-wrappers/get-patterns/get-pnpm-patterns.ts create mode 100644 src/commands/lib/get-wrappers/get-patterns/get-yarn-patterns.ts create mode 100644 src/commands/lib/get-wrappers/get-patterns/index.ts create mode 100644 src/commands/lib/get-wrappers/get-patterns/props.ts create mode 100644 src/commands/lib/get-wrappers/get-patterns/read-json-safe.ts create mode 100644 src/commands/lib/get-wrappers/get-patterns/read-yaml-safe.ts rename src/commands/lib/{ => get-wrappers}/get-wrappers.spec.ts (88%) create mode 100644 src/commands/lib/get-wrappers/index.ts create mode 100644 src/commands/lib/get-wrappers/readonly.ts create mode 100644 src/commands/lib/get-wrappers/tap.ts create mode 100644 src/commands/lib/get-wrappers/try-catch.ts diff --git a/jest.config.js b/jest.config.js index 194ad86a..73836221 100644 --- a/jest.config.js +++ b/jest.config.js @@ -4,10 +4,10 @@ module.exports = { coverageReporters: ['html', 'lcov'], coverageThreshold: { global: { - branches: 90, - functions: 82, - lines: 89, - statements: 84, + branches: 89, + functions: 89, + lines: 93, + statements: 92, }, }, moduleFileExtensions: ['ts', 'tsx', 'js'], diff --git a/package.json b/package.json index e07075d2..69d01282 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "commander": "8.1.0", "cosmiconfig": "7.0.0", "expect-more": "1.1.0", + "fp-ts": "2.11.2", "fs-extra": "10.0.0", "glob": "7.1.7", "read-yaml-file": "2.1.0", diff --git a/src/commands/fix-mismatches.ts b/src/commands/fix-mismatches.ts index 973baea4..2330e061 100644 --- a/src/commands/fix-mismatches.ts +++ b/src/commands/fix-mismatches.ts @@ -2,7 +2,7 @@ import chalk from 'chalk'; import { writeFileSync } from 'fs-extra'; import { EOL } from 'os'; import { relative } from 'path'; -import { SyncpackConfig } from '../constants'; +import { CWD, SyncpackConfig } from '../constants'; import { getHighestVersion } from './lib/get-highest-version'; import { getWrappers, SourceWrapper } from './lib/get-wrappers'; import { getMismatchedDependencies } from './lib/installations/get-mismatched-dependencies'; @@ -43,7 +43,7 @@ export const fixMismatchesToDisk = (options: Options): void => { fixMismatches(wrappers, options); wrappers.forEach((wrapper, i) => { - const shortPath = relative(process.cwd(), wrapper.filePath); + const shortPath = relative(CWD, wrapper.filePath); const before = allBefore[i]; const after = toJson(wrapper); if (before !== after) { diff --git a/src/commands/lib/get-wrappers.ts b/src/commands/lib/get-wrappers.ts deleted file mode 100644 index dc93f91f..00000000 --- a/src/commands/lib/get-wrappers.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { isArrayOfStrings } from 'expect-more'; -import { readFileSync, readJsonSync } from 'fs-extra'; -import { sync } from 'glob'; -import { join, resolve } from 'path'; -import { sync as readYamlFileSync } from 'read-yaml-file'; -import { ALL_PATTERNS } from '../../constants'; - -interface Options { - source: string[]; -} - -export interface Source { - bugs?: { url: string } | string; - dependencies?: { [key: string]: string }; - description?: string; - devDependencies?: { [key: string]: string }; - keywords?: string[]; - name?: string; - peerDependencies?: { [key: string]: string }; - repository?: { type: string; url: string } | string; - resolutions?: { [key: string]: string }; - scripts?: { [key: string]: string }; - version?: string; - workspaces?: string[] | { [key: string]: string[] }; - [otherProps: string]: string | string[] | { [key: string]: string | string[] } | undefined; -} - -export interface SourceWrapper { - /** the absolute path on disk to this package.json file */ - filePath: string; - /** the parsed JSON contents of this package.json file */ - contents: Source; - /** the raw file contents of this package.json file */ - json: string; -} - -const getPatternsFromJson = ( - fileName: string, - getProperties: (config: any) => Array, -): string[] | null => { - const filePath = resolve(process.cwd(), fileName); - const config = readJsonSync(filePath, { throws: false }); - if (!config) return null; - const packages = getProperties(config).find(isArrayOfStrings); - return packages ? [process.cwd()].concat(packages).map((dirPath) => join(dirPath, 'package.json')) : null; -}; - -const getCliPatterns = (program: Options): Options['source'] | null => - isArrayOfStrings(program.source) ? program.source : null; - -const getYarnPatterns = (): string[] | null => - getPatternsFromJson('package.json', (config) => [config.workspaces, config.workspaces?.packages]); - -const getLernaPatterns = (): string[] | null => getPatternsFromJson('lerna.json', (config) => [config.packages]); - -const getPnpmPatterns = (): string[] | null => { - try { - const filePath = resolve(process.cwd(), 'pnpm-workspace.yaml'); - const config = readYamlFileSync<{ packages?: string[] }>(filePath); - const packages = [config.packages].find(isArrayOfStrings); - return packages ? [process.cwd()].concat(packages).map((dirPath) => join(dirPath, 'package.json')) : null; - } catch (err) { - return null; - } -}; - -const getDefaultPatterns = (): string[] => ALL_PATTERNS; -const resolvePattern = (pattern: string): string[] => sync(pattern, { absolute: true }); -const reduceFlatArray = (all: string[], next: string[]): string[] => all.concat(next); -const createWrapper = (filePath: string): SourceWrapper => { - const json = readFileSync(filePath, { encoding: 'utf8' }); - return { - contents: JSON.parse(json), - filePath, - json, - }; -}; - -export const getWrappers = (program: Options): SourceWrapper[] => - (getCliPatterns(program) || getYarnPatterns() || getPnpmPatterns() || getLernaPatterns() || getDefaultPatterns()) - .map(resolvePattern) - .reduce(reduceFlatArray, []) - .map(createWrapper); diff --git a/src/commands/lib/get-wrappers/get-file-paths.ts b/src/commands/lib/get-wrappers/get-file-paths.ts new file mode 100644 index 00000000..9c0afb00 --- /dev/null +++ b/src/commands/lib/get-wrappers/get-file-paths.ts @@ -0,0 +1,43 @@ +import { isArrayOfStrings } from 'expect-more'; +import * as E from 'fp-ts/lib/Either'; +import { flow, pipe } from 'fp-ts/lib/function'; +import * as O from 'fp-ts/lib/Option'; +import { sync as globSync } from 'glob'; +import { CWD } from '../../../constants'; +import { getPatterns, Options } from './get-patterns'; +import { removeReadonlyType } from './readonly'; +import { tapNone } from './tap'; +import { getErrorOrElse } from './try-catch'; + +type MaybeFilePaths = O.Option; +type EitherMaybeFilePaths = E.Either; + +/** + * Using --source options and/or config files on disk from npm/pnpm/yarn/lerna, + * return an array of absolute paths to every package.json file the user is + * working with. + * + * @returns Array of absolute file paths to package.json files + */ +export function getFilePaths(program: Options): EitherMaybeFilePaths { + return pipe( + getPatterns(program), + E.traverseArray(resolvePattern), + E.map(flow(removeReadonlyType, mergeArrayOfOptionsIntoOne, O.filter(isArrayOfStrings))), + ); + + function resolvePattern(pattern: string): EitherMaybeFilePaths { + return pipe( + E.tryCatch( + () => globSync(pattern, { absolute: true, cwd: CWD }), + getErrorOrElse(`npm package "glob" threw on pattern "${pattern}"`), + ), + E.map(flow(O.of, O.filter(isArrayOfStrings), tapNone(`found 0 files matching pattern "${pattern}"`))), + ); + } + + function mergeArrayOfOptionsIntoOne(options: MaybeFilePaths[]): MaybeFilePaths { + const unwrap = O.getOrElse(() => []); + return O.of(options.reduce((values, option) => values.concat(unwrap(option)), [])); + } +} diff --git a/src/commands/lib/get-wrappers/get-patterns/get-lerna-patterns.ts b/src/commands/lib/get-wrappers/get-patterns/get-lerna-patterns.ts new file mode 100644 index 00000000..14ec13a2 --- /dev/null +++ b/src/commands/lib/get-wrappers/get-patterns/get-lerna-patterns.ts @@ -0,0 +1,20 @@ +import { isArrayOfStrings } from 'expect-more'; +import * as E from 'fp-ts/lib/Either'; +import { flow, pipe } from 'fp-ts/lib/function'; +import * as O from 'fp-ts/lib/Option'; +import { join } from 'path'; +import { MaybePatterns } from '.'; +import { CWD } from '../../../../constants'; +import { props } from './props'; +import { readJsonSafe } from './read-json-safe'; + +export function getLernaPatterns(): MaybePatterns { + return pipe( + readJsonSafe(join(CWD, 'lerna.json')), + E.map(flow(props('contents.packages'), O.filter(isArrayOfStrings))), + E.match( + (): MaybePatterns => O.none, + (value) => value, + ), + ); +} diff --git a/src/commands/lib/get-wrappers/get-patterns/get-pnpm-patterns.ts b/src/commands/lib/get-wrappers/get-patterns/get-pnpm-patterns.ts new file mode 100644 index 00000000..7b114f6f --- /dev/null +++ b/src/commands/lib/get-wrappers/get-patterns/get-pnpm-patterns.ts @@ -0,0 +1,28 @@ +import { isArrayOfStrings } from 'expect-more'; +import * as E from 'fp-ts/lib/Either'; +import { flow, pipe } from 'fp-ts/lib/function'; +import * as O from 'fp-ts/lib/Option'; +import { join } from 'path'; +import type { MaybePatterns } from '.'; +import { CWD } from '../../../../constants'; +import { props } from './props'; +import { readYamlSafe } from './read-yaml-safe'; + +interface PnpmWorkspace { + packages?: string[]; +} + +export function getPnpmPatterns(): MaybePatterns { + return pipe( + // packages: + // - "packages/**" + // - "components/**" + // - "!**/test/**" + readYamlSafe(join(CWD, 'pnpm-workspace.yaml')), + E.map(flow(props('packages'), O.filter(isArrayOfStrings))), + E.match( + (): MaybePatterns => O.none, + (value) => value, + ), + ); +} diff --git a/src/commands/lib/get-wrappers/get-patterns/get-yarn-patterns.ts b/src/commands/lib/get-wrappers/get-patterns/get-yarn-patterns.ts new file mode 100644 index 00000000..032f0850 --- /dev/null +++ b/src/commands/lib/get-wrappers/get-patterns/get-yarn-patterns.ts @@ -0,0 +1,30 @@ +import { isArrayOfStrings } from 'expect-more'; +import * as E from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/function'; +import * as O from 'fp-ts/lib/Option'; +import { join } from 'path'; +import type { MaybePatterns } from '.'; +import { Source } from '..'; +import { CWD } from '../../../../constants'; +import { props } from './props'; +import { readJsonSafe } from './read-json-safe'; + +export function getYarnPatterns(): MaybePatterns { + return pipe( + readJsonSafe(join(CWD, 'package.json')), + E.map((file) => pipe(findPackages(file.contents))), + O.fromEither, + O.flatten, + ); + + function findPackages(yarn: Source): MaybePatterns { + return pipe( + getArrayOfStrings('workspaces', yarn), + O.fold(() => getArrayOfStrings('workspaces.packages', yarn), O.some), + ); + } + + function getArrayOfStrings(paths: string, yarn: Source): MaybePatterns { + return pipe(yarn, props(paths), O.filter(isArrayOfStrings)); + } +} diff --git a/src/commands/lib/get-wrappers/get-patterns/index.ts b/src/commands/lib/get-wrappers/get-patterns/index.ts new file mode 100644 index 00000000..e6044ef9 --- /dev/null +++ b/src/commands/lib/get-wrappers/get-patterns/index.ts @@ -0,0 +1,50 @@ +import { isArrayOfStrings } from 'expect-more'; +import { flow, pipe } from 'fp-ts/lib/function'; +import * as O from 'fp-ts/lib/Option'; +import { join } from 'path'; +import { ALL_PATTERNS, CWD, SyncpackConfig } from '../../../../constants'; +import { tapNone } from '../tap'; +import { getLernaPatterns } from './get-lerna-patterns'; +import { getPnpmPatterns } from './get-pnpm-patterns'; +import { getYarnPatterns } from './get-yarn-patterns'; + +type Patterns = string[]; + +export type Options = Pick; +export type MaybePatterns = O.Option; + +/** + * Find every glob pattern which should be used to find package.json files for + * this monorepo. + * + * @returns `['./package.json', './packages/* /package.json']` + */ +export function getPatterns(program: Options): Patterns { + return pipe( + O.of(program.source), + O.filter(isArrayOfStrings), + tapNone('no --source patterns found'), + O.fold( + flow( + getYarnPatterns, + tapNone('no yarn workspaces found'), + O.fold(getPnpmPatterns, O.of), + tapNone('no pnpm workspaces found'), + O.fold(getLernaPatterns, O.of), + tapNone('no lerna packages found'), + O.map(flow(addRootDir, limitToPackageJson)), + ), + O.of, + ), + tapNone('no patterns found, using defaults'), + O.getOrElse(() => ALL_PATTERNS), + ); + + function addRootDir(patterns: Patterns): Patterns { + return [CWD, ...patterns]; + } + + function limitToPackageJson(patterns: Patterns): Patterns { + return patterns.map((pattern) => join(pattern, 'package.json')); + } +} diff --git a/src/commands/lib/get-wrappers/get-patterns/props.ts b/src/commands/lib/get-wrappers/get-patterns/props.ts new file mode 100644 index 00000000..3e5d85bb --- /dev/null +++ b/src/commands/lib/get-wrappers/get-patterns/props.ts @@ -0,0 +1,19 @@ +import { pipe } from 'fp-ts/lib/function'; +import * as O from 'fp-ts/lib/Option'; +import * as C from 'fp-ts/lib/ReadonlyRecord'; +import * as S from 'fp-ts/lib/State'; + +/** + * Safely read nested properties of any value. + * @param keys 'child.grandChild.greatGrandChild' + * @see https://gist.github.com/JamieMason/c0a3b21184cf8c43f76c77878c7c9198 + */ +export function props(keys: string) { + return function getNestedProp(obj: unknown): O.Option { + return pipe( + keys.split('.'), + S.traverseArray((key: string) => S.modify(O.chain(C.lookup(key) as never))), + S.execute(O.fromNullable(obj)), + ); + }; +} diff --git a/src/commands/lib/get-wrappers/get-patterns/read-json-safe.ts b/src/commands/lib/get-wrappers/get-patterns/read-json-safe.ts new file mode 100644 index 00000000..0b4af9a8 --- /dev/null +++ b/src/commands/lib/get-wrappers/get-patterns/read-json-safe.ts @@ -0,0 +1,26 @@ +import { parse } from 'fp-ts/Json'; +import * as E from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/function'; +import { readFileSync } from 'fs-extra'; +import { SourceWrapper } from '..'; +import { getErrorOrElse } from '../try-catch'; + +export function readJsonSafe(filePath: string): E.Either { + return pipe( + readFileSafe(filePath), + E.chain((json) => + pipe( + parse(json), + E.mapLeft(getErrorOrElse(`Failed to parse JSON file at ${filePath}`)), + E.map((contents) => ({ contents, filePath, json } as SourceWrapper)), + ), + ), + ); +} + +function readFileSafe(filePath: string): E.Either { + return E.tryCatch( + () => readFileSync(filePath, { encoding: 'utf8' }), + getErrorOrElse(`Failed to read JSON file at ${filePath}`), + ); +} diff --git a/src/commands/lib/get-wrappers/get-patterns/read-yaml-safe.ts b/src/commands/lib/get-wrappers/get-patterns/read-yaml-safe.ts new file mode 100644 index 00000000..a3380ffa --- /dev/null +++ b/src/commands/lib/get-wrappers/get-patterns/read-yaml-safe.ts @@ -0,0 +1,7 @@ +import * as E from 'fp-ts/lib/Either'; +import { sync as readYamlSync } from 'read-yaml-file'; +import { getErrorOrElse } from '../try-catch'; + +export function readYamlSafe(filePath: string): E.Either { + return E.tryCatch(() => readYamlSync(filePath), getErrorOrElse(`Failed to read YAML file at ${filePath}`)); +} diff --git a/src/commands/lib/get-wrappers.spec.ts b/src/commands/lib/get-wrappers/get-wrappers.spec.ts similarity index 88% rename from src/commands/lib/get-wrappers.spec.ts rename to src/commands/lib/get-wrappers/get-wrappers.spec.ts index 33237d4e..d1d2b68f 100644 --- a/src/commands/lib/get-wrappers.spec.ts +++ b/src/commands/lib/get-wrappers/get-wrappers.spec.ts @@ -1,7 +1,8 @@ import { removeSync } from 'fs-extra'; -import { getWrappers, SourceWrapper } from './get-wrappers'; +import { getWrappers, SourceWrapper } from '.'; import mock = require('mock-fs'); -import { toJson, withJson } from '../../../test/mock'; +import { toJson, withJson } from '../../../../test/mock'; +import { CWD } from '../../../constants'; describe('getWrappers', () => { afterEach(() => { @@ -28,7 +29,7 @@ describe('getWrappers', () => { const getShape = (name: string, filePath: string): SourceWrapper => withJson({ contents: { name }, - filePath: `${process.cwd()}/${filePath}`, + filePath: `${CWD}/${filePath}`, }); it('prefers CLI', () => { @@ -39,6 +40,11 @@ describe('getWrappers', () => { ]); }); + it('returns empty array when no patterns match', () => { + const program = { source: ['typo.json'] }; + expect(getWrappers(program)).toEqual([]); + }); + it('falls back to lerna.json if present', () => { const program = { source: [] }; expect(getWrappers(program)).toEqual([ @@ -75,7 +81,7 @@ describe('getWrappers', () => { it('should resolve correctly', () => { const program = { source: [] }; expect(getWrappers(program)).toEqual([ - withJson({ contents: { workspaces: ['as-array/*'] }, filePath: `${process.cwd()}/package.json` }), + withJson({ contents: { workspaces: ['as-array/*'] }, filePath: `${CWD}/package.json` }), getShape('packages-a', 'as-array/a/package.json'), getShape('packages-b', 'as-array/b/package.json'), ]); @@ -96,7 +102,7 @@ describe('getWrappers', () => { expect(getWrappers(program)).toEqual([ withJson({ contents: { workspaces: { packages: ['as-object/*'] } }, - filePath: `${process.cwd()}/package.json`, + filePath: `${CWD}/package.json`, }), getShape('packages-a', 'as-object/a/package.json'), getShape('packages-b', 'as-object/b/package.json'), @@ -122,7 +128,7 @@ describe('getWrappers', () => { it('should resolve correctly', () => { const program = { source: [] }; expect(getWrappers(program)).toEqual([ - withJson({ contents: { name: 'root' }, filePath: `${process.cwd()}/package.json` }), + withJson({ contents: { name: 'root' }, filePath: `${CWD}/package.json` }), getShape('package-a', 'a/package.json'), getShape('package-b', 'b/package.json'), ]); diff --git a/src/commands/lib/get-wrappers/index.ts b/src/commands/lib/get-wrappers/index.ts new file mode 100644 index 00000000..2257ec0d --- /dev/null +++ b/src/commands/lib/get-wrappers/index.ts @@ -0,0 +1,46 @@ +import * as E from 'fp-ts/lib/Either'; +import * as O from 'fp-ts/lib/Option'; +import { flow, pipe } from 'fp-ts/lib/function'; +import { SyncpackConfig } from '../../../constants'; +import { getFilePaths } from './get-file-paths'; +import { readJsonSafe } from './get-patterns/read-json-safe'; +import { removeReadonlyType } from './readonly'; + +export interface Source { + bugs?: { url: string } | string; + dependencies?: { [key: string]: string }; + description?: string; + devDependencies?: { [key: string]: string }; + keywords?: string[]; + name?: string; + peerDependencies?: { [key: string]: string }; + repository?: { type: string; url: string } | string; + resolutions?: { [key: string]: string }; + scripts?: { [key: string]: string }; + version?: string; + workspaces?: string[] | { [key: string]: string[] }; + [otherProps: string]: string | string[] | { [key: string]: string | string[] } | undefined; +} + +export interface SourceWrapper { + /** the absolute path on disk to this package.json file */ + filePath: string; + /** the parsed JSON contents of this package.json file */ + contents: Source; + /** the raw file contents of this package.json file */ + json: string; +} + +type Options = Pick; + +/** + * Read the file contents and metadata for every package.json file needed. + */ +export function getWrappers(program: Options): SourceWrapper[] { + const useEmpty = () => []; + return pipe( + getFilePaths(program), + E.chain(flow(O.getOrElse(useEmpty as () => string[]), E.traverseArray(readJsonSafe), E.map(removeReadonlyType))), + E.fold(useEmpty as () => SourceWrapper[], (wrappers) => wrappers), + ); +} diff --git a/src/commands/lib/get-wrappers/readonly.ts b/src/commands/lib/get-wrappers/readonly.ts new file mode 100644 index 00000000..029ea78d --- /dev/null +++ b/src/commands/lib/get-wrappers/readonly.ts @@ -0,0 +1,6 @@ +/** + * Remove unwanted readonly type added by TaskEither.traverseArray + */ +export function removeReadonlyType(value: readonly T[]): T[] { + return value as T[]; +} diff --git a/src/commands/lib/get-wrappers/tap.ts b/src/commands/lib/get-wrappers/tap.ts new file mode 100644 index 00000000..933a9c6a --- /dev/null +++ b/src/commands/lib/get-wrappers/tap.ts @@ -0,0 +1,14 @@ +import { yellow } from 'chalk'; +import * as O from 'fp-ts/lib/Option'; + +/** + * Log a message when a pipeline contains `None` and let it continue unchanged. + */ +export function tapNone(message: string): (ma: O.Option) => O.Option { + return O.fold>(function logNoneValue() { + if (process.env.SYNCPACK_VERBOSE === 'true') { + console.log(yellow(`? ${message}`)); + } + return O.none; + }, O.of); +} diff --git a/src/commands/lib/get-wrappers/try-catch.ts b/src/commands/lib/get-wrappers/try-catch.ts new file mode 100644 index 00000000..6ef01f7e --- /dev/null +++ b/src/commands/lib/get-wrappers/try-catch.ts @@ -0,0 +1,9 @@ +/** + * When using `Either.tryCatch` or `TaskEither.tryCatch`, prefer using the more + * relevant upstream `Error` when available, otherwise create our own. + */ +export function getErrorOrElse(message: string): (reason: unknown) => Error { + return function onThrow(err) { + return err instanceof Error ? err : new Error(message); + }; +} diff --git a/src/commands/lib/write-if-changed.ts b/src/commands/lib/write-if-changed.ts index 9da14936..48f957c7 100644 --- a/src/commands/lib/write-if-changed.ts +++ b/src/commands/lib/write-if-changed.ts @@ -2,6 +2,7 @@ import chalk from 'chalk'; import { writeFileSync } from 'fs-extra'; import { EOL } from 'os'; import { relative } from 'path'; +import { CWD } from '../../constants'; import { SourceWrapper } from './get-wrappers'; import { log } from './log'; @@ -9,7 +10,7 @@ const toJson = (indent: string, wrapper: SourceWrapper): string => `${JSON.stringify(wrapper.contents, null, indent)}${EOL}`; export const writeIfChanged = (indent: string, wrapper: SourceWrapper, mutateContents: () => void): void => { - const shortPath = relative(process.cwd(), wrapper.filePath); + const shortPath = relative(CWD, wrapper.filePath); mutateContents(); const after = toJson(indent, wrapper); if (wrapper.json !== after) { diff --git a/src/constants.ts b/src/constants.ts index f2ddb57c..6393d89b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,6 +3,8 @@ import { collect } from './lib/collect'; export type DependencyType = 'dependencies' | 'devDependencies' | 'peerDependencies'; export const DEPENDENCY_TYPES: DependencyType[] = ['dependencies', 'devDependencies', 'peerDependencies']; +export const CWD = process.cwd(); + export const GREATER = 1; export const LESSER = -1; export const SAME = 0; diff --git a/yarn.lock b/yarn.lock index ce05f09a..b7d491ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1887,6 +1887,11 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +fp-ts@2.11.2: + version "2.11.2" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.11.2.tgz#a3f5f74ac56f16c412044470a5fe3b51b94816dc" + integrity sha512-G1rD89nmbbgTNRBKohjB3Qv4IxOHQ5KV3ZvYfpaQZyrGt+ZQUFrcnCqE567bcEdvwoAUKDQM7isOcv7xcM/qAQ== + fs-extra@10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1"