* feat(core): switch over to devkit 10-rc.0 * feat(core): implement solution tsconfigs wip * feat(angular): add angular migrations * fix(angular): modify angularjs tests
217 lines
6.0 KiB
TypeScript
217 lines
6.0 KiB
TypeScript
import { join, Path, strings } from '@angular-devkit/core';
|
|
import {
|
|
apply,
|
|
chain,
|
|
mergeWith,
|
|
move,
|
|
noop,
|
|
Rule,
|
|
SchematicContext,
|
|
template,
|
|
Tree,
|
|
url,
|
|
} from '@angular-devkit/schematics';
|
|
import '@nrwl/tao/src/compat/compat';
|
|
import { formatFiles, getWorkspace, names, toFileName } from '@nrwl/workspace';
|
|
import {
|
|
addDepsToPackageJson,
|
|
addGlobal,
|
|
getProjectConfig,
|
|
insert,
|
|
readJsonInTree,
|
|
} from '@nrwl/workspace/src/utils/ast-utils';
|
|
import { toJS } from '@nrwl/workspace/src/utils/rules/to-js';
|
|
import * as path from 'path';
|
|
import * as ts from 'typescript';
|
|
import { addReduxStoreToMain, updateReduxStore } from '../../utils/ast-utils';
|
|
import {
|
|
reactReduxVersion,
|
|
reduxjsToolkitVersion,
|
|
typesReactReduxVersion,
|
|
} from '../../utils/versions';
|
|
import { NormalizedSchema, Schema } from './schema';
|
|
|
|
export default function (schema: any): Rule {
|
|
return async (host: Tree, context: SchematicContext) => {
|
|
const options = await normalizeOptions(host, schema);
|
|
|
|
return chain([
|
|
generateReduxFiles(options),
|
|
addExportsToBarrel(options),
|
|
addReduxPackageDependencies,
|
|
addStoreConfiguration(options, context),
|
|
updateReducerConfiguration(options, context),
|
|
formatFiles(),
|
|
]);
|
|
};
|
|
}
|
|
|
|
function generateReduxFiles(options: NormalizedSchema) {
|
|
const templateSource = apply(url('./files'), [
|
|
template({ ...options, tmpl: '' }),
|
|
move(options.filesPath),
|
|
options.js ? toJS() : noop(),
|
|
]);
|
|
|
|
return mergeWith(templateSource);
|
|
}
|
|
|
|
function addReduxPackageDependencies(): Rule {
|
|
return addDepsToPackageJson(
|
|
{
|
|
'@reduxjs/toolkit': reduxjsToolkitVersion,
|
|
'react-redux': reactReduxVersion,
|
|
'@types/react-redux': typesReactReduxVersion,
|
|
},
|
|
{}
|
|
);
|
|
}
|
|
|
|
function addExportsToBarrel(options: NormalizedSchema): Rule {
|
|
return (host: Tree) => {
|
|
const indexFilePath = path.join(
|
|
options.projectSourcePath,
|
|
options.js ? 'index.js' : 'index.ts'
|
|
);
|
|
|
|
const buffer = host.read(indexFilePath);
|
|
if (!!buffer) {
|
|
const indexSource = buffer.toString('utf-8');
|
|
const indexSourceFile = ts.createSourceFile(
|
|
indexFilePath,
|
|
indexSource,
|
|
ts.ScriptTarget.Latest,
|
|
true
|
|
);
|
|
|
|
const statePath = options.directory
|
|
? `./lib/${options.directory}/${options.fileName}`
|
|
: `./lib/${options.fileName}`;
|
|
|
|
insert(host, indexFilePath, [
|
|
...addGlobal(
|
|
indexSourceFile,
|
|
indexFilePath,
|
|
`export * from '${statePath}.slice';`
|
|
),
|
|
]);
|
|
}
|
|
|
|
return host;
|
|
};
|
|
}
|
|
|
|
function addStoreConfiguration(
|
|
options: NormalizedSchema,
|
|
context: SchematicContext
|
|
) {
|
|
return options.appProjectSourcePath
|
|
? (host: Tree) => {
|
|
const mainSource = host.read(options.appMainFilePath).toString();
|
|
if (!mainSource.includes('redux')) {
|
|
const mainSourceFile = ts.createSourceFile(
|
|
options.appMainFilePath,
|
|
mainSource,
|
|
ts.ScriptTarget.Latest,
|
|
true
|
|
);
|
|
insert(
|
|
host,
|
|
options.appMainFilePath,
|
|
addReduxStoreToMain(
|
|
options.appMainFilePath,
|
|
mainSourceFile,
|
|
context
|
|
)
|
|
);
|
|
}
|
|
return host;
|
|
}
|
|
: noop();
|
|
}
|
|
|
|
function updateReducerConfiguration(
|
|
options: NormalizedSchema,
|
|
context: SchematicContext
|
|
) {
|
|
return options.appProjectSourcePath
|
|
? (host: Tree) => {
|
|
const mainSource = host.read(options.appMainFilePath).toString();
|
|
const mainSourceFile = ts.createSourceFile(
|
|
options.appMainFilePath,
|
|
mainSource,
|
|
ts.ScriptTarget.Latest,
|
|
true
|
|
);
|
|
insert(
|
|
host,
|
|
options.appMainFilePath,
|
|
updateReduxStore(options.appMainFilePath, mainSourceFile, context, {
|
|
keyName: `${options.constantName}_FEATURE_KEY`,
|
|
reducerName: `${options.propertyName}Reducer`,
|
|
modulePath: `${options.projectModulePath}`,
|
|
})
|
|
);
|
|
return host;
|
|
}
|
|
: noop();
|
|
}
|
|
|
|
async function normalizeOptions(
|
|
host: Tree,
|
|
options: Schema
|
|
): Promise<NormalizedSchema> {
|
|
let appProjectSourcePath: Path;
|
|
let appMainFilePath: string;
|
|
const extraNames = names(options.name);
|
|
const { sourceRoot } = getProjectConfig(host, options.project);
|
|
const workspace = await getWorkspace(host);
|
|
const projectType = workspace.projects.get(options.project).extensions
|
|
.projectType as string;
|
|
const tsConfigJson = readJsonInTree(host, 'tsconfig.base.json');
|
|
const tsPaths: { [module: string]: string[] } = tsConfigJson.compilerOptions
|
|
? tsConfigJson.compilerOptions.paths || {}
|
|
: {};
|
|
const modulePath =
|
|
projectType === 'application'
|
|
? `./app/${extraNames.fileName}.slice`
|
|
: Object.keys(tsPaths).find((k) =>
|
|
tsPaths[k].some((s) => s.includes(sourceRoot))
|
|
);
|
|
// If --project is set to an app, automatically configure store
|
|
// for it without needing to specify --appProject.
|
|
options.appProject =
|
|
options.appProject ||
|
|
(projectType === 'application' ? options.project : undefined);
|
|
if (options.appProject) {
|
|
const appConfig = getProjectConfig(host, options.appProject);
|
|
if (appConfig.projectType !== 'application') {
|
|
throw new Error(
|
|
`Expected ${options.appProject} to be an application but got ${appConfig.projectType}`
|
|
);
|
|
}
|
|
appProjectSourcePath = appConfig.sourceRoot;
|
|
appMainFilePath = path.join(
|
|
appProjectSourcePath,
|
|
options.js ? 'main.js' : 'main.tsx'
|
|
);
|
|
if (!host.exists(appMainFilePath)) {
|
|
throw new Error(
|
|
`Could not find ${appMainFilePath} during store configuration`
|
|
);
|
|
}
|
|
}
|
|
return {
|
|
...options,
|
|
...extraNames,
|
|
constantName: strings.underscore(options.name).toUpperCase(),
|
|
directory: toFileName(options.directory),
|
|
projectType,
|
|
projectSourcePath: sourceRoot,
|
|
projectModulePath: modulePath,
|
|
appProjectSourcePath,
|
|
appMainFilePath,
|
|
filesPath: join(sourceRoot, projectType === 'application' ? 'app' : 'lib'),
|
|
};
|
|
}
|