-
-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(schematics): support for schematics
- Loading branch information
Showing
8 changed files
with
321 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Rule, Tree } from '@angular-devkit/schematics'; | ||
import { getWorkspace } from '@schematics/angular/utility/config'; | ||
import { Schema } from './schema'; | ||
import { getProjectFromWorkspace } from '../utils/get-project'; | ||
import { getProjectTargetOptions } from '../utils/get-project-target'; | ||
|
||
const hammerjsImportStatement = `import 'hammerjs';`; | ||
|
||
/** Adds HammerJS to the main file of the specified Angular CLI project. */ | ||
export function addHammerJsToMain(options: Schema): Rule { | ||
return (host: Tree) => { | ||
const workspace = getWorkspace(host); | ||
const project = getProjectFromWorkspace(workspace, options.project); | ||
const mainFile = getProjectTargetOptions(project, 'build').main; | ||
|
||
const recorder = host.beginUpdate(mainFile); | ||
const buffer = host.read(mainFile); | ||
|
||
if (!buffer) { | ||
return console.error(`Could not read the project main file (${mainFile}). Please manually ` + | ||
`import HammerJS in your main TypeScript file.`); | ||
} | ||
|
||
const fileContent = buffer.toString('utf8'); | ||
|
||
if (fileContent.includes(hammerjsImportStatement)) { | ||
return console.log(`HammerJS is already imported in the project main file (${mainFile}).`); | ||
} | ||
|
||
recorder.insertRight(0, `${hammerjsImportStatement}\n`); | ||
host.commitUpdate(recorder); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"$schema": "http://json-schema.org/schema", | ||
"id": "alyle-ui-ng-add", | ||
"title": "Alyle UI ng-add schematic", | ||
"type": "object", | ||
"properties": { | ||
"project": { | ||
"type": "string", | ||
"description": "Name of the project.", | ||
"$default": { | ||
"$source": "projectName" | ||
} | ||
}, | ||
"gestures": { | ||
"type": "boolean", | ||
"default": true, | ||
"description": "Whether gesture support should be set up.", | ||
"x-prompt": "Set up HammerJS for gesture recognition?" | ||
}, | ||
"themes": { | ||
"type": "array", | ||
"x-prompt": { | ||
"message": "Select the themes that will be added to AppModule", | ||
"type": "list", | ||
"multiselect": true, | ||
"items": [ | ||
{ | ||
"value": "minima-light", "label": "Minima Light" | ||
}, | ||
{ | ||
"value": "minima-dark", "label": "Minima Dark" | ||
} | ||
] | ||
} | ||
} | ||
}, | ||
"required": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export interface Schema { | ||
project: string; | ||
gestures: boolean; | ||
themes: string[]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
import * as inquirer from 'inquirer'; | ||
import * as semver from 'semver'; | ||
import { strings } from '@angular-devkit/core'; | ||
import * as ts from '@schematics/angular/node_modules/typescript/lib/typescript'; | ||
import { addSymbolToNgModuleMetadata, insertImport, isImported } from '@schematics/angular/utility/ast-utils'; | ||
import { getAppModulePath } from '@schematics/angular/utility/ng-ast-utils'; | ||
import { getProjectTargets, targetBuildNotFoundError } from '@schematics/angular/utility/project-targets'; | ||
import { InsertChange } from '@schematics/angular/utility/change'; | ||
import { join } from 'path'; | ||
import { Observable } from 'rxjs'; | ||
import { | ||
Rule, | ||
SchematicContext, | ||
SchematicsException, | ||
Tree | ||
} from '@angular-devkit/schematics'; | ||
import { Schema } from './schema'; | ||
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; | ||
|
||
checkVersionAngularCLI(); | ||
|
||
function checkVersionAngularCLI() { | ||
const version = require(join(process.cwd(), 'package.json')).devDependencies['@angular/cli']; | ||
if (!semver.satisfies(semver.coerce(version)!, '>=7.2.0-rc.0 || 7.2.x')) { | ||
throw new SchematicsException(`Alyle UI Schematics require "@angular/cli@>=7.2.0-rc.0 || 7.2.x"`); | ||
} | ||
} | ||
|
||
function updateAppModule(host: Tree, _context: SchematicContext, options: any, themeName: string, themes: string[]) { | ||
_context.logger.debug('Updating appmodule'); | ||
// find app module | ||
const projectTargets = getProjectTargets(host, options.project); | ||
if (!projectTargets.build) { | ||
throw targetBuildNotFoundError(); | ||
} | ||
|
||
const mainPath = projectTargets.build.options.main; | ||
const modulePath = getAppModulePath(host, mainPath); | ||
_context.logger.debug(`module path: ${modulePath}`); | ||
|
||
// add import animations | ||
let moduleSource = getTsSourceFile(host, modulePath); | ||
let importModule = 'BrowserAnimationsModule'; | ||
let importPath = '@angular/platform-browser/animations'; | ||
if (!isImported(moduleSource, importModule, importPath)) { | ||
const change = insertImport | ||
(moduleSource, modulePath, importModule, importPath); | ||
if (change) { | ||
const recorder = host.beginUpdate(modulePath); | ||
recorder.insertLeft((change as InsertChange).pos, (change as InsertChange).toAdd); | ||
host.commitUpdate(recorder); | ||
} | ||
} | ||
|
||
// register animations in app module | ||
moduleSource = getTsSourceFile(host, modulePath); | ||
let metadataChanges = addSymbolToNgModuleMetadata( | ||
moduleSource, modulePath, 'imports', importModule); | ||
if (metadataChanges) { | ||
const recorder = host.beginUpdate(modulePath); | ||
metadataChanges.forEach((change: InsertChange) => { | ||
recorder.insertRight(change.pos, change.toAdd); | ||
}); | ||
host.commitUpdate(recorder); | ||
} | ||
|
||
// add import theme | ||
['LyThemeModule', 'LY_THEME'].forEach((_import) => { | ||
moduleSource = getTsSourceFile(host, modulePath); | ||
importModule = _import; | ||
importPath = '@alyle/ui'; | ||
if (!isImported(moduleSource, importModule, importPath)) { | ||
const change = insertImport | ||
(moduleSource, modulePath, importModule, importPath); | ||
if (change) { | ||
const recorder = host.beginUpdate(modulePath); | ||
recorder.insertLeft((change as InsertChange).pos, (change as InsertChange).toAdd); | ||
host.commitUpdate(recorder); | ||
} | ||
} | ||
}); | ||
|
||
// register theme in app module | ||
const importText = `LyThemeModule.setTheme('${themeName}')`; | ||
moduleSource = getTsSourceFile(host, modulePath); | ||
metadataChanges = addSymbolToNgModuleMetadata( | ||
moduleSource, modulePath, 'imports', importText); | ||
if (!moduleSource.text.includes('LyThemeModule.setTheme') && metadataChanges) { | ||
const recorder = host.beginUpdate(modulePath); | ||
metadataChanges.forEach((change: InsertChange) => { | ||
recorder.insertRight(change.pos, change.toAdd); | ||
}); | ||
host.commitUpdate(recorder); | ||
} | ||
|
||
themes.forEach(_themeName => { | ||
const [themePath] = _themeName.split('-'); | ||
// register providers | ||
moduleSource = getTsSourceFile(host, modulePath); | ||
const simbolName = `{ provide: LY_THEME, useClass: ${strings.classify(_themeName)}, multi: true }`; | ||
metadataChanges = addSymbolToNgModuleMetadata( | ||
moduleSource, modulePath, 'providers', simbolName); | ||
if (metadataChanges) { | ||
const recorder = host.beginUpdate(modulePath); | ||
metadataChanges.forEach((change: InsertChange) => { | ||
recorder.insertRight(change.pos, change.toAdd); | ||
}); | ||
host.commitUpdate(recorder); | ||
} | ||
|
||
// add import themes | ||
moduleSource = getTsSourceFile(host, modulePath); | ||
importModule = strings.classify(_themeName); | ||
importPath = `@alyle/ui/themes/${themePath}`; | ||
if (!isImported(moduleSource, importModule, importPath)) { | ||
const change = insertImport | ||
(moduleSource, modulePath, importModule, importPath); | ||
if (change) { | ||
const recorder = host.beginUpdate(modulePath); | ||
recorder.insertLeft((change as InsertChange).pos, (change as InsertChange).toAdd); | ||
host.commitUpdate(recorder); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
function getTsSourceFile(host: Tree, path: string): ts.SourceFile { | ||
const buffer = host.read(path); | ||
if (!buffer) { | ||
throw new SchematicsException(`Could not read file (${path}).`); | ||
} | ||
const content = buffer.toString(); | ||
const source = ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true); | ||
|
||
return source; | ||
} | ||
|
||
|
||
// You don't have to export the function as default. You can also have more than one rule factory | ||
// per file. | ||
export function setUpAppModule(_options: Schema): Rule { | ||
return (host: Tree, _context: SchematicContext) => { | ||
return new Observable((_) => { | ||
if (_options.themes.length > 1) { | ||
inquirer | ||
.prompt([ | ||
{ | ||
type: 'list', | ||
name: 'selectedTheme', | ||
message: 'Set Theme', | ||
choices: _options.themes | ||
}, | ||
]) | ||
.then(({selectedTheme}: { selectedTheme: string }) => { | ||
const themes = _options.themes; | ||
updateAppModule(host, _context, _options, selectedTheme, themes); | ||
_.next(host); | ||
_.complete(); | ||
_context.addTask(new NodePackageInstallTask()); | ||
}); | ||
} else { | ||
const selectedTheme = [...(_options.themes as string[]), 'minima-light'][0]; | ||
updateAppModule(host, _context, _options, selectedTheme, [selectedTheme]); | ||
_.next(host); | ||
_.complete(); | ||
_context.addTask(new NodePackageInstallTask()); | ||
} | ||
}); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import {WorkspaceProject} from '@angular-devkit/core/src/workspace'; | ||
import {SchematicsException} from '@angular-devkit/schematics'; | ||
|
||
/** Resolves the architect options for the build target of the given project. */ | ||
export function getProjectTargetOptions(project: WorkspaceProject, buildTarget: string) { | ||
const targets = project.targets || project.architect; | ||
if (targets && | ||
targets[buildTarget] && | ||
targets[buildTarget].options) { | ||
|
||
return targets[buildTarget].options; | ||
} | ||
|
||
throw new SchematicsException( | ||
`Cannot determine project target configuration for: ${buildTarget}.`); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { WorkspaceSchema, WorkspaceProject } from '@angular-devkit/core/src/workspace'; | ||
import { SchematicsException } from '@angular-devkit/schematics'; | ||
|
||
/** | ||
* Finds the specified project configuration in the workspace. Throws an error if the project | ||
* couldn't be found. | ||
*/ | ||
export function getProjectFromWorkspace( | ||
workspace: WorkspaceSchema, | ||
projectName?: string): WorkspaceProject { | ||
|
||
const project = workspace.projects[projectName || workspace.defaultProject!]; | ||
|
||
if (!project) { | ||
throw new SchematicsException(`Could not find project in workspace: ${projectName}`); | ||
} | ||
|
||
return project; | ||
} |