Skip to content

Commit

Permalink
feat(linter): move move logic to linter
Browse files Browse the repository at this point in the history
  • Loading branch information
meeroslav committed Aug 22, 2023
1 parent 8e90737 commit 5c3ab1b
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 119 deletions.
93 changes: 93 additions & 0 deletions packages/linter/src/generators/utils/eslint-file.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
joinPathFragments,
names,
offsetFromRoot,
readJson,
Tree,
updateJson,
Expand Down Expand Up @@ -59,6 +60,98 @@ export function isEslintConfigSupported(tree: Tree, projectRoot = ''): boolean {
return eslintFile.endsWith('.json') || eslintFile.endsWith('.config.js');
}

export function updateRelativePathsInConfig(
tree: Tree,
sourcePath: string,
destinationPath: string
) {
if (
sourcePath === destinationPath ||
!isEslintConfigSupported(tree, destinationPath)
) {
return;
}

const configPath = joinPathFragments(
destinationPath,
findEslintFile(tree, destinationPath)
);
const offset = offsetFromRoot(destinationPath);

if (useFlatConfig(tree)) {
const config = tree.read(configPath, 'utf-8');
tree.write(
configPath,
replaceFlatConfigPaths(config, sourcePath, offset, destinationPath)
);
} else {
updateJson(tree, configPath, (json) => {
if (typeof json.extends === 'string') {
json.extends = offsetFilePath(sourcePath, json.extends, offset);
} else if (json.extends) {
json.extends = json.extends.map((extend: string) =>
offsetFilePath(sourcePath, extend, offset)
);
}

json.overrides?.forEach(
(o: { parserOptions?: { project?: string | string[] } }) => {
if (o.parserOptions?.project) {
o.parserOptions.project = Array.isArray(o.parserOptions.project)
? o.parserOptions.project.map((p) =>
p.replace(sourcePath, destinationPath)
)
: o.parserOptions.project.replace(sourcePath, destinationPath);
}
}
);
return json;
});
}
}

function replaceFlatConfigPaths(
config: string,
sourceRoot: string,
offset: string,
destinationRoot: string
): string {
let match;
let newConfig = config;

// replace requires
const requireRegex = RegExp(/require\(['"](.*)['"]\)/g);
while ((match = requireRegex.exec(newConfig)) !== null) {
const newPath = offsetFilePath(sourceRoot, match[1], offset);
newConfig =
newConfig.slice(0, match.index) +
`require('${newPath}')` +
newConfig.slice(match.index + match[0].length);
}
// replace projects
const projectRegex = RegExp(/project:\s?\[?['"](.*)['"]\]?/g);
while ((match = projectRegex.exec(newConfig)) !== null) {
const newProjectDef = match[0].replaceAll(sourceRoot, destinationRoot);
newConfig =
newConfig.slice(0, match.index) +
newProjectDef +
newConfig.slice(match.index + match[0].length);
}
return newConfig;
}

function offsetFilePath(
projectRoot: string,
pathToFile: string,
offset: string
): string {
if (!pathToFile.startsWith('..')) {
// not a relative path
return pathToFile;
}
return joinPathFragments(offset, projectRoot, pathToFile);
}

export function addOverrideToLintConfig(
tree: Tree,
root: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ describe('updateEslint (flat config)', () => {
};

tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
tree.delete('.eslintrc.json');
tree.write('eslint.config.js', `module.exports = [];`);
});

it('should handle config not existing', async () => {
Expand Down
133 changes: 14 additions & 119 deletions packages/workspace/src/generators/move/lib/update-eslint-config.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,6 @@
import {
joinPathFragments,
offsetFromRoot,
ProjectConfiguration,
Tree,
updateJson,
} from '@nx/devkit';
import { join } from 'path';
import { ensurePackage, ProjectConfiguration, Tree } from '@nx/devkit';
import { NormalizedSchema } from '../schema';

interface PartialEsLintrcOverride {
parserOptions?: {
project?: string[];
};
}

interface PartialEsLintRcJson {
extends: string | string[];
overrides?: PartialEsLintrcOverride[];
}

function offsetFilePath(
project: ProjectConfiguration,
pathToFile: string,
offset: string
): string {
if (!pathToFile.startsWith('..')) {
// not a relative path
return pathToFile;
}
const pathFromRoot = join(project.root, pathToFile);
return joinPathFragments(offset, pathFromRoot);
}
import { nxVersion } from '../../../utils/versions';

/**
* Update the .eslintrc file of the project if it exists.
Expand All @@ -42,93 +12,18 @@ export function updateEslintConfig(
schema: NormalizedSchema,
project: ProjectConfiguration
) {
const offset = offsetFromRoot(schema.relativeToRootDestination);
const eslintJsonPath = join(
schema.relativeToRootDestination,
'.eslintrc.json'
);

if (tree.exists(eslintJsonPath)) {
return updateJson<PartialEsLintRcJson>(
tree,
eslintJsonPath,
(eslintRcJson) => {
if (typeof eslintRcJson.extends === 'string') {
eslintRcJson.extends = offsetFilePath(
project,
eslintRcJson.extends,
offset
);
} else if (eslintRcJson.extends) {
eslintRcJson.extends = eslintRcJson.extends.map((extend: string) =>
offsetFilePath(project, extend, offset)
);
}

eslintRcJson.overrides?.forEach(
(o: { parserOptions?: { project?: string | string[] } }) => {
if (o.parserOptions?.project) {
o.parserOptions.project = Array.isArray(o.parserOptions.project)
? o.parserOptions.project.map((p) =>
p.replace(project.root, schema.relativeToRootDestination)
)
: o.parserOptions.project.replace(
project.root,
schema.relativeToRootDestination
);
}
}
);
return eslintRcJson;
}
);
// if there is no suitable eslint config, we don't need to do anything
if (!tree.exists('.eslintrc.json') && !tree.exists('eslint.config.js')) {
return;
}

const eslintFlatPath = join(
schema.relativeToRootDestination,
'eslint.config.js'
ensurePackage('@nx/linter', nxVersion);
const {
updateRelativePathsInConfig,
// nx-ignore-next-line
} = require('@nx/linter/src/generators/utils/eslint-file');
updateRelativePathsInConfig(
tree,
project.root,
schema.relativeToRootDestination
);
if (tree.exists(eslintFlatPath)) {
const config = tree.read(eslintFlatPath, 'utf-8');
tree.write(
eslintFlatPath,
replaceFlatConfigPaths(
config,
project,
offset,
schema.relativeToRootDestination
)
);
}
}

function replaceFlatConfigPaths(
config: string,
project: ProjectConfiguration,
offset: string,
pathToDestination: string
): string {
let match;
let newConfig = config;

// replace requires
const requireRegex = RegExp(/require\(['"](.*)['"]\)/g);
while ((match = requireRegex.exec(newConfig)) !== null) {
const newPath = offsetFilePath(project, match[1], offset);
newConfig =
newConfig.slice(0, match.index) +
`require('${newPath}')` +
newConfig.slice(match.index + match[0].length);
}
// replace projects
const projectRegex = RegExp(/project:\s?\[?['"](.*)['"]\]?/g);
while ((match = projectRegex.exec(newConfig)) !== null) {
const newProjectDef = match[0].replaceAll(project.root, pathToDestination);
newConfig =
newConfig.slice(0, match.index) +
newProjectDef +
newConfig.slice(match.index + match[0].length);
}

return newConfig;
}

0 comments on commit 5c3ab1b

Please sign in to comment.