Skip to content

Commit

Permalink
feat: sort library and sub-app names to reduce git merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
xpol committed Dec 9, 2024
1 parent a0efb93 commit f23f3c1
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 2 deletions.
50 changes: 50 additions & 0 deletions src/lib/library/library.factory.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EmptyTree, Tree } from '@angular-devkit/schematics';
import {
SchematicTestRunner,
UnitTestTree,
Expand Down Expand Up @@ -80,4 +81,53 @@ describe('Library Factory', () => {
'/libs/project/src/project.service.spec.js',
]);
});

it('should sort library names in nest-cli.json, package.json and tsconfig.json', async () => {
const options: LibraryOptions[] = [
{
name: 'c',
language: 'ts',
prefix: 'app',
},
{
name: 'a',
language: 'ts',
prefix: 'app',
},
{
name: 'b',
language: 'ts',
prefix: 'app',
}
];

let tree: Tree = new EmptyTree();
tree.create('/package.json', `{"name": "my-pacakge","version": "1.0.0","jest": {}}`);
tree.create('/tsconfig.json', `{compilerOptions: {}}`);


for (const o of options) {
tree = await runner.runSchematic('library', o, tree);
}

const packageJson = tree.readJson('/package.json');
expect(packageJson['jest']['moduleNameMapper']).toEqual([
'^app/a(|/.*)$',
'^app/b(|/.*)$',
'^app/c(|/.*)$'
]); // Sorted jest.moduleNameMapper by keys

const tsConfigJson = tree.readJson('/tsconfig.json');
expect(tsConfigJson['compilerOptions']['paths']).toEqual([
'app/a',
'app/a/*',
'app/b',
'app/b/*',
'app/c',
'app/c/*'
]); // Sorted compilerOptions.paths by keys

const config = tree.readJson('/nest-cli.json');
expect(Object.keys(config['projects'])).toEqual(['a', 'b', 'c']); // Sorted
});
});
10 changes: 9 additions & 1 deletion src/lib/library/library.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
url,
} from '@angular-devkit/schematics';
import { parse } from 'jsonc-parser';
import { normalizeToKebabOrSnakeCase } from '../../utils/formatting';
import { inPlaceSortByKeys, normalizeToKebabOrSnakeCase } from '../../utils';
import {
DEFAULT_LANGUAGE,
DEFAULT_LIB_PATH,
Expand Down Expand Up @@ -133,6 +133,8 @@ function updateJestConfig(
const packageKeyRegex = '^' + packageKey + '(|/.*)$';
const packageRoot = join('<rootDir>' as Path, distRoot);
jestOptions.moduleNameMapper[packageKeyRegex] = join(packageRoot, '$1');

inPlaceSortByKeys(jestOptions.moduleNameMapper);
}

function updateNpmScripts(
Expand Down Expand Up @@ -181,6 +183,8 @@ function updateJestEndToEnd(options: LibraryOptions) {
const packageRoot = '<rootDir>/../' + distRoot;
jestOptions.moduleNameMapper[deepPackagePath] = packageRoot + '/$1';
jestOptions.moduleNameMapper[packageKey] = packageRoot;

inPlaceSortByKeys(jestOptions.moduleNameMapper);
},
);
};
Expand Down Expand Up @@ -238,6 +242,8 @@ function updateTsConfig(
tsconfig.compilerOptions.paths[deepPackagePath] = [];
}
tsconfig.compilerOptions.paths[deepPackagePath].push(distRoot + '/*');

inPlaceSortByKeys(tsconfig.compilerOptions.paths);
},
);
};
Expand Down Expand Up @@ -284,6 +290,8 @@ function addLibraryToCliOptions(
);
}
optionsFile.projects[projectName] = project;

inPlaceSortByKeys(optionsFile.projects);
},
);
};
Expand Down
29 changes: 29 additions & 0 deletions src/lib/sub-app/sub-app.factory.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { EmptyTree, Tree } from '@angular-devkit/schematics';
import {
SchematicTestRunner,
UnitTestTree,
} from '@angular-devkit/schematics/testing';
import * as path from 'path';
import { LibraryOptions } from '../library/library.schema';
import { SubAppOptions } from './sub-app.schema';

describe('SubApp Factory', () => {
Expand Down Expand Up @@ -126,4 +128,31 @@ describe('SubApp Factory', () => {
].sort(),
);
});

it('should sort sub-app names in nest-cli.json', async () => {
const options: SubAppOptions[] = [
{
name: 'c',
language: 'ts',
},
{
name: 'a',
language: 'ts',
},
{
name: 'b',
language: 'ts',
}
];

let tree: Tree = new EmptyTree();
tree.create('/nest-cli.json', `{"monorepo": true, "projects": {}}`);

for (const o of options) {
tree = await runner.runSchematic('sub-app', o, tree);
}

const config = tree.readJson('/nest-cli.json');
expect(Object.keys(config['projects'])).toEqual(['a', 'b', 'c']); // Sorted
});
});
6 changes: 5 additions & 1 deletion src/lib/sub-app/sub-app.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from '@angular-devkit/schematics';
import { existsSync, readFileSync } from 'fs';
import { parse, stringify } from 'comment-json';
import { normalizeToKebabOrSnakeCase } from '../../utils/formatting';
import { inPlaceSortByKeys, normalizeToKebabOrSnakeCase } from '../../utils';
import {
DEFAULT_APPS_PATH,
DEFAULT_APP_NAME,
Expand Down Expand Up @@ -150,6 +150,8 @@ function updateTsConfig() {
if (!tsconfig.compilerOptions.paths) {
tsconfig.compilerOptions.paths = {};
}

inPlaceSortByKeys(tsconfig.compilerOptions.paths);
},
);
};
Expand Down Expand Up @@ -324,6 +326,8 @@ function addAppsToCliOptions(
);
}
optionsFile.projects[projectName] = project;

inPlaceSortByKeys(optionsFile.projects);
},
);
};
Expand Down
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './name.parser';
export * from './path.solver';
export * from './source-root.helpers';
export * from './formatting';
export * from './object-sorting';
17 changes: 17 additions & 0 deletions src/utils/object-sorting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* In-place sort object entities by their keys so that it can be serialized to json with sorted order.
* @param object
* @returns The original object with modified entities order.
*/
export function inPlaceSortByKeys(object: Record<string, any>): Record<string, any> {
const sorted: Record<string, any> = {};

const keys = Object.keys(object);
keys.sort();
for (const key of keys) {
sorted[key] = object[key];
delete object[key];
}

return Object.assign(object, sorted);
}
14 changes: 14 additions & 0 deletions test/utils/object-sorting.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { inPlaceSortByKeys } from '../../src/utils/object-sorting';


describe('inPlaceSortByKeys', () => {
it('should in-place sort the entities by their keys', () => {
const input = { z: 'z', b: 'b', c: 'c', a: 'a', };
expect(Object.keys(input)).toEqual(['z', 'b', 'c', 'a']);

const got = inPlaceSortByKeys(input);

expect(got).toBe(input); // Same object
expect(Object.keys(got)).toEqual(['a', 'b', 'c', 'z']);
})
})

0 comments on commit f23f3c1

Please sign in to comment.