Skip to content

Commit

Permalink
feat(tools): implement tsconfig-base-all generator
Browse files Browse the repository at this point in the history
  • Loading branch information
Hotell committed Apr 18, 2023
1 parent f08032b commit 8213eb3
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 66 deletions.
20 changes: 14 additions & 6 deletions tools/generators/tsconfig-base-all/README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
# tsconfig-base-all

Workspace Generator ...TODO...
Workspace Generator for generating/updating `/tsconfig.base.all.json`.

> `tsconfig.base.all.json` contains all monorepo project path aliases, and reflect source of truth for all monorepo packages.
<!-- toc -->

- [Usage](#usage)
- [Examples](#examples)
- [Options](#options)
- [`name`](#name)
- [`verify`](#verify)

<!-- tocstop -->

## Usage

```sh
yarn nx workspace-generator tsconfig-base-all ...
yarn nx workspace-generator tsconfig-base-all
```

Show what will be generated without writing to disk:
Expand All @@ -31,8 +33,14 @@ yarn nx workspace-generator tsconfig-base-all

## Options

#### `name`
#### `verify`

Type: `boolean`

Type: `string`
use this option on CI to check if base.all.json is up to date and in sync with all other base configs

TODO...
Following will throw an error if `tsconfig.base.all.json` is out of date

```sh
yarn nx workspace-generator tsconfig-base-all --verify
```

This file was deleted.

115 changes: 108 additions & 7 deletions tools/generators/tsconfig-base-all/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,121 @@
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { Tree, readProjectConfiguration } from '@nrwl/devkit';
import { Tree, writeJson, readJson, updateJson } from '@nrwl/devkit';

import generator from './index';
import { TsconfigBaseAllGeneratorSchema } from './schema';

describe('tsconfig-base-all generator', () => {
let appTree: Tree;
const options: TsconfigBaseAllGeneratorSchema = { name: 'test' };
let tree: Tree;
const options: TsconfigBaseAllGeneratorSchema = {};

beforeEach(() => {
appTree = createTreeWithEmptyWorkspace();
tree = createTreeWithEmptyWorkspace();
writeJson(tree, '/tsconfig.base.v0.json', {
compilerOptions: {
paths: {
'@proj/v0-one': ['packages/v0-one/src/index.ts'],
'@proj/v0-two': ['packages/v0-two/src/index.ts'],
},
},
});
writeJson(tree, '/tsconfig.base.v8.json', {
compilerOptions: {
paths: {
'@proj/v8-one': ['packages/v8-one/src/index.ts'],
'@proj/v8-two': ['packages/v8-two/src/index.ts'],
},
},
});
writeJson(tree, '/tsconfig.base.json', {
compilerOptions: {
paths: {
'@proj/one': ['packages/one/src/index.ts'],
'@proj/two': ['packages/two/src/index.ts'],
},
},
});
});

it('should run successfully', async () => {
await generator(appTree, options);
const config = readProjectConfiguration(appTree, 'test');
expect(config).toBeDefined();
await generator(tree, options);
const baseAllJson = readJson(tree, '/tsconfig.base.all.json');

expect(baseAllJson).toMatchInlineSnapshot(`
Object {
"compilerOptions": Object {
"baseUrl": ".",
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"moduleResolution": "node",
"paths": Object {
"@proj/one": Array [
"packages/one/src/index.ts",
],
"@proj/two": Array [
"packages/two/src/index.ts",
],
"@proj/v0-one": Array [
"packages/v0-one/src/index.ts",
],
"@proj/v0-two": Array [
"packages/v0-two/src/index.ts",
],
"@proj/v8-one": Array [
"packages/v8-one/src/index.ts",
],
"@proj/v8-two": Array [
"packages/v8-two/src/index.ts",
],
},
"preserveConstEnums": true,
"pretty": true,
"rootDir": ".",
"skipLibCheck": true,
"sourceMap": true,
"typeRoots": Array [
"node_modules/@types",
"./typings",
],
},
}
`);
});

describe(`--verify`, () => {
it(`should pass if base all config is up to date`, async () => {
expect.assertions(1);
await generator(tree, {});

updateJson(tree, '/tsconfig.base.json', json => {
json.compilerOptions.paths['@proj/three'] = ['packages/three/src/index.ts'];
return json;
});

await generator(tree, {});

await expect(generator(tree, { verify: true })).resolves.toBe(undefined);
});

it(`should fail if base all config is not up to date`, async () => {
expect.assertions(1);
await generator(tree, {});

updateJson(tree, '/tsconfig.base.json', json => {
json.compilerOptions.paths['@proj/three'] = ['packages/three/src/index.ts'];
return json;
});

try {
await generator(tree, { verify: true });
} catch (err) {
expect((err as Error).message).toMatchInlineSnapshot(`
"
🚨 /tsconfig.base.all.json is out of date.
Please update it by running 'yarn nx workspace-generator tsconfig-base-all'.
"
`);
}
});
});
});
49 changes: 16 additions & 33 deletions tools/generators/tsconfig-base-all/index.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,33 @@
import * as path from 'path';
import { Tree, formatFiles, installPackagesTask, names, generateFiles } from '@nrwl/devkit';
import { libraryGenerator } from '@nrwl/workspace/generators';

import { getProjectConfig } from '../../utils';
import { Tree, formatFiles, writeJson } from '@nrwl/devkit';
import { isEqual } from 'lodash';

import { TsconfigBaseAllGeneratorSchema } from './schema';
import { createPathAliasesConfig } from './lib/utils';

// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface NormalizedSchema extends ReturnType<typeof normalizeOptions> {}

export default async function (tree: Tree, schema: TsconfigBaseAllGeneratorSchema) {
await libraryGenerator(tree, { name: schema.name });

const normalizedOptions = normalizeOptions(tree, schema);

addFiles(tree, normalizedOptions);
const { existingTsConfig, mergedTsConfig, tsConfigAllPath } = createPathAliasesConfig(tree);

await formatFiles(tree);
if (normalizedOptions.verify && !isEqual(existingTsConfig, mergedTsConfig)) {
throw new Error(`
🚨 ${tsConfigAllPath} is out of date.
return () => {
installPackagesTask(tree);
};
Please update it by running 'yarn nx workspace-generator tsconfig-base-all'.
`);
}

writeJson(tree, tsConfigAllPath, mergedTsConfig);
await formatFiles(tree);
}

function normalizeOptions(tree: Tree, options: TsconfigBaseAllGeneratorSchema) {
const project = getProjectConfig(tree, { packageName: options.name });

const defaults = { verify: false };
return {
...defaults,
...options,
...project,
...names(options.name),
};
}

/**
* NOTE: remove this if your generator doesn't process any static/dynamic templates
*/
function addFiles(tree: Tree, options: NormalizedSchema) {
const templateOptions = {
...options,
tmpl: '',
};

generateFiles(
tree,
path.join(__dirname, 'files'),
path.join(options.projectConfig.root, options.name),
templateOptions,
);
}
7 changes: 0 additions & 7 deletions tools/generators/tsconfig-base-all/lib/utils.spec.ts

This file was deleted.

39 changes: 37 additions & 2 deletions tools/generators/tsconfig-base-all/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
// use this module to define any kind of generic utilities that are used in more than 1 place within the generator implementation
import * as path from 'path';
import { readJson, Tree } from '@nrwl/devkit';

export function dummyHelper() {
return;
/**
*
* Create tsconfig.json with merged "compilerOptions.paths" from v0,v8,v9 tsconfigs.
*/
export function createPathAliasesConfig(tree: Tree) {
const tsConfigAllPath = '/tsconfig.base.all.json';
const existingTsConfig = tree.exists(tsConfigAllPath) ? readJson(tree, tsConfigAllPath) : null;

const baseConfigs = {
v0: readJson(tree, path.join('/tsconfig.base.v0.json')),
v8: readJson(tree, path.join('/tsconfig.base.v8.json')),
v9: readJson(tree, path.join('/tsconfig.base.json')),
};
const tsConfigBase = '.';
const mergedTsConfig = {
compilerOptions: {
moduleResolution: 'node',
forceConsistentCasingInFileNames: true,
skipLibCheck: true,
typeRoots: ['node_modules/@types', './typings'],
isolatedModules: true,
preserveConstEnums: true,
sourceMap: true,
pretty: true,
rootDir: tsConfigBase,
baseUrl: tsConfigBase,
paths: {
...baseConfigs.v0.compilerOptions.paths,
...baseConfigs.v8.compilerOptions.paths,
...baseConfigs.v9.compilerOptions.paths,
},
},
};

return { tsConfigAllPath, mergedTsConfig, existingTsConfig };
}
13 changes: 5 additions & 8 deletions tools/generators/tsconfig-base-all/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@
"$schema": "http://json-schema.org/schema",
"cli": "nx",
"id": "tsconfig-base-all",
"description": "Create tsconfig.json with merged 'compilerOptions.paths' from v0,v8,v9 tsconfigs",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Library name",
"$default": {
"$source": "argv",
"index": 0
}
"verify": {
"type": "boolean",
"description": "Verify integrity of tsconfig.base.all.json path aliases"
}
},
"required": ["name"]
"required": []
}
4 changes: 2 additions & 2 deletions tools/generators/tsconfig-base-all/schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface TsconfigBaseAllGeneratorSchema {
/**
* Library name
* Verify integrity of tsconfig.base.all.json path aliases
*/
name: string;
verify?: boolean;
}

0 comments on commit 8213eb3

Please sign in to comment.