Skip to content

Commit 797a384

Browse files
committedDec 9, 2024·
feat: sort library and sub-app names to reduce git merge conflicts
1 parent a0efb93 commit 797a384

File tree

7 files changed

+127
-2
lines changed

7 files changed

+127
-2
lines changed
 

‎src/lib/library/library.factory.test.ts

+52
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { EmptyTree, Tree } from '@angular-devkit/schematics';
12
import {
23
SchematicTestRunner,
34
UnitTestTree,
@@ -80,4 +81,55 @@ describe('Library Factory', () => {
8081
'/libs/project/src/project.service.spec.js',
8182
]);
8283
});
84+
85+
it('should sort library names in nest-cli.json, package.json and tsconfig.json', async () => {
86+
const options: LibraryOptions[] = [
87+
{
88+
name: 'c',
89+
language: 'ts',
90+
prefix: 'app',
91+
},
92+
{
93+
name: 'a',
94+
language: 'ts',
95+
prefix: 'app',
96+
},
97+
{
98+
name: 'b',
99+
language: 'ts',
100+
prefix: 'app',
101+
}
102+
];
103+
104+
let tree: Tree = new EmptyTree();
105+
tree.create('/package.json', `{"name": "my-pacakge","version": "1.0.0","jest": {}}`);
106+
tree.create('/tsconfig.json', `{compilerOptions: {}}`);
107+
108+
109+
for (const o of options) {
110+
tree = await runner.runSchematic('library', o, tree);
111+
}
112+
113+
const packageJson = tree.readJson('/package.json');
114+
const moduleNameMapper = packageJson['jest']['moduleNameMapper'];
115+
expect(Object.keys(moduleNameMapper)).toEqual([
116+
'^app/a(|/.*)$',
117+
'^app/b(|/.*)$',
118+
'^app/c(|/.*)$'
119+
]); // Sorted jest.moduleNameMapper by keys
120+
121+
const tsConfigJson = tree.readJson('/tsconfig.json');
122+
const paths = tsConfigJson['compilerOptions']['paths'];
123+
expect(Object.keys(paths)).toEqual([
124+
'app/a',
125+
'app/a/*',
126+
'app/b',
127+
'app/b/*',
128+
'app/c',
129+
'app/c/*'
130+
]); // Sorted compilerOptions.paths by keys
131+
132+
const config = tree.readJson('/nest-cli.json');
133+
expect(Object.keys(config['projects'])).toEqual(['a', 'b', 'c']); // Sorted
134+
});
83135
});

‎src/lib/library/library.factory.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
url,
1414
} from '@angular-devkit/schematics';
1515
import { parse } from 'jsonc-parser';
16-
import { normalizeToKebabOrSnakeCase } from '../../utils/formatting';
16+
import { inPlaceSortByKeys, normalizeToKebabOrSnakeCase } from '../../utils';
1717
import {
1818
DEFAULT_LANGUAGE,
1919
DEFAULT_LIB_PATH,
@@ -133,6 +133,8 @@ function updateJestConfig(
133133
const packageKeyRegex = '^' + packageKey + '(|/.*)$';
134134
const packageRoot = join('<rootDir>' as Path, distRoot);
135135
jestOptions.moduleNameMapper[packageKeyRegex] = join(packageRoot, '$1');
136+
137+
inPlaceSortByKeys(jestOptions.moduleNameMapper);
136138
}
137139

138140
function updateNpmScripts(
@@ -181,6 +183,8 @@ function updateJestEndToEnd(options: LibraryOptions) {
181183
const packageRoot = '<rootDir>/../' + distRoot;
182184
jestOptions.moduleNameMapper[deepPackagePath] = packageRoot + '/$1';
183185
jestOptions.moduleNameMapper[packageKey] = packageRoot;
186+
187+
inPlaceSortByKeys(jestOptions.moduleNameMapper);
184188
},
185189
);
186190
};
@@ -238,6 +242,8 @@ function updateTsConfig(
238242
tsconfig.compilerOptions.paths[deepPackagePath] = [];
239243
}
240244
tsconfig.compilerOptions.paths[deepPackagePath].push(distRoot + '/*');
245+
246+
inPlaceSortByKeys(tsconfig.compilerOptions.paths);
241247
},
242248
);
243249
};
@@ -284,6 +290,8 @@ function addLibraryToCliOptions(
284290
);
285291
}
286292
optionsFile.projects[projectName] = project;
293+
294+
inPlaceSortByKeys(optionsFile.projects);
287295
},
288296
);
289297
};

‎src/lib/sub-app/sub-app.factory.test.ts

+29
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import { EmptyTree, Tree } from '@angular-devkit/schematics';
12
import {
23
SchematicTestRunner,
34
UnitTestTree,
45
} from '@angular-devkit/schematics/testing';
56
import * as path from 'path';
7+
import { LibraryOptions } from '../library/library.schema';
68
import { SubAppOptions } from './sub-app.schema';
79

810
describe('SubApp Factory', () => {
@@ -126,4 +128,31 @@ describe('SubApp Factory', () => {
126128
].sort(),
127129
);
128130
});
131+
132+
it('should sort sub-app names in nest-cli.json', async () => {
133+
const options: SubAppOptions[] = [
134+
{
135+
name: 'c',
136+
language: 'ts',
137+
},
138+
{
139+
name: 'a',
140+
language: 'ts',
141+
},
142+
{
143+
name: 'b',
144+
language: 'ts',
145+
}
146+
];
147+
148+
let tree: Tree = new EmptyTree();
149+
tree.create('/nest-cli.json', `{"monorepo": true, "projects": {}}`);
150+
151+
for (const o of options) {
152+
tree = await runner.runSchematic('sub-app', o, tree);
153+
}
154+
155+
const config = tree.readJson('/nest-cli.json');
156+
expect(Object.keys(config['projects'])).toEqual(['a', 'b', 'c']); // Sorted
157+
});
129158
});

‎src/lib/sub-app/sub-app.factory.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
} from '@angular-devkit/schematics';
1717
import { existsSync, readFileSync } from 'fs';
1818
import { parse, stringify } from 'comment-json';
19-
import { normalizeToKebabOrSnakeCase } from '../../utils/formatting';
19+
import { inPlaceSortByKeys, normalizeToKebabOrSnakeCase } from '../../utils';
2020
import {
2121
DEFAULT_APPS_PATH,
2222
DEFAULT_APP_NAME,
@@ -150,6 +150,8 @@ function updateTsConfig() {
150150
if (!tsconfig.compilerOptions.paths) {
151151
tsconfig.compilerOptions.paths = {};
152152
}
153+
154+
inPlaceSortByKeys(tsconfig.compilerOptions.paths);
153155
},
154156
);
155157
};
@@ -324,6 +326,8 @@ function addAppsToCliOptions(
324326
);
325327
}
326328
optionsFile.projects[projectName] = project;
329+
330+
inPlaceSortByKeys(optionsFile.projects);
327331
},
328332
);
329333
};

‎src/utils/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export * from './name.parser';
77
export * from './path.solver';
88
export * from './source-root.helpers';
99
export * from './formatting';
10+
export * from './object-sorting';

‎src/utils/object-sorting.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* In-place sort object entities by their keys so that it can be serialized to json with sorted order.
3+
* @param object
4+
* @returns The original object with modified entities order.
5+
*/
6+
export function inPlaceSortByKeys(object: Record<string, any>): Record<string, any> {
7+
const sorted: Record<string, any> = {};
8+
9+
const keys = Object.keys(object);
10+
keys.sort();
11+
for (const key of keys) {
12+
sorted[key] = object[key];
13+
delete object[key];
14+
}
15+
16+
return Object.assign(object, sorted);
17+
}

‎test/utils/object-sorting.test.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { inPlaceSortByKeys } from '../../src/utils/object-sorting';
2+
3+
4+
describe('inPlaceSortByKeys', () => {
5+
it('should in-place sort the entities by their keys', () => {
6+
const input = { z: 'z', b: 'b', c: 'c', a: 'a', };
7+
expect(Object.keys(input)).toEqual(['z', 'b', 'c', 'a']);
8+
9+
const got = inPlaceSortByKeys(input);
10+
11+
expect(got).toBe(input); // Same object
12+
expect(Object.keys(got)).toEqual(['a', 'b', 'c', 'z']);
13+
})
14+
})

0 commit comments

Comments
 (0)
Please sign in to comment.