diff --git a/projects/angular-material-extensions/select-icon/README.md b/projects/angular-material-extensions/select-icon/README.md deleted file mode 100644 index 20589a3..0000000 --- a/projects/angular-material-extensions/select-icon/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# SelectIcon - -This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.0.14. - -## Code scaffolding - -Run `ng generate component component-name --project select-icon` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project select-icon`. -> Note: Don't forget to add `--project select-icon` or else it will be added to the default project in your `angular.json` file. - -## Build - -Run `ng build select-icon` to build the project. The build artifacts will be stored in the `dist/` directory. - -## Publishing - -After building your library with `ng build select-icon`, go to the dist folder `cd dist/select-icon` and run `npm publish`. - -## Running unit tests - -Run `ng test select-icon` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/projects/angular-material-extensions/select-icon/package.json b/projects/angular-material-extensions/select-icon/package.json index 3a47662..7e4cfea 100644 --- a/projects/angular-material-extensions/select-icon/package.json +++ b/projects/angular-material-extensions/select-icon/package.json @@ -1,11 +1,86 @@ { "name": "@angular-material-extensions/select-icon", "version": "0.0.1", + "homepage": "https://angular-material-extensions.github.io/select-icon", + "author": { + "name": "anthonynahas", + "url": "https://github.com/anthonynahas" + }, + "repository": { + "type": "git", + "url": "https://github.com/angular-material-extensions/select-icon.git" + }, + "license": "MIT", + "schematics": "./schematics/collection.json", + "keywords": [ + "ng", + "library", + "angular", + "material", + "material design", + "ssr", + "select icon", + "icon picker", + "icon button", + "image button" + ], + "bugs": { + "url": "https://github.com/angular-material-extensions/select-icon/issues" + }, + "scripts": { + "build": "../../../node_modules/.bin/ng build @angular-material-extensions/select-icon --prod", + "build:schematics": "../../../node_modules/.bin/tsc -p tsconfig.schematics.json", + "clean": "rm -rf ../../../dist", + "lint": "../../../node_modules/.bin/ng lint @angular-material-extensions/select-icon", + "resync:schematics": "rsync -a schematics/collection.json ../../../dist/angular-material-extensions/select-icon/schematics/", + "resync:readme": "rsync -a ../../../README.md ../../../dist/angular-material-extensions/select-icon/", + "postbuild": "npm run build:schematics && npm run resync:readme && npm run resync:schematics", + "prepublish": "npm run build", + "release:patch": "../../../node_modules/.bin/release-it --patch --ci ", + "release:minor": "../../../node_modules/.bin/release-it --minor --ci", + "release:major": "../../../node_modules/.bin/release-it --major --ci --no-git.requireCleanWorkingDir", + "release:version": "../../../node_modules/.bin/release-it 2.2.0 --ci --no-git.requireCleanWorkingDir", + "ng:test": "../../../node_modules/.bin/ng test @angular-material-extensions/select-icon", + "test": "../../../node_modules/.bin/jest --coverage", + "test:watch": "../../../node_modules/.bin/jest --coverage --watch" + }, "peerDependencies": { "@angular/common": "^10.0.14", - "@angular/core": "^10.0.14" + "@angular/core": "^10.0.14", + "@angular/cdk": "~10.1.0", + "@angular/material": "~10.1.0" }, "dependencies": { "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10.13" + }, + "release-it": { + "github": { + "release": true + }, + "npm": { + "publish": true, + "publishPath": "../../../dist/angular-material-extensions/select-country" + }, + "publishConfig": { + "access": "public" + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": "angular", + "infile": "../../../CHANGELOG.md" + } + }, + "hooks": { + "before:init": [ + "npm run clean" + ], + "after:bump": "echo \"building lib v${version}... \" && npm run build", + "before:git:release": "echo \"Updating CHANGELOG.md for v${version} \" && git commit -m \"Updating CHANGELOG.md for v${version} \" ../../../CHANGELOG.md", + "after:release": "echo Successfully released ${name} v${version} to ${repo.repository}.", + "before:npm": "echo building the library..." + } } -} \ No newline at end of file +} diff --git a/projects/angular-material-extensions/select-icon/schematics/collection.json b/projects/angular-material-extensions/select-icon/schematics/collection.json new file mode 100755 index 0000000..817e2e9 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/collection.json @@ -0,0 +1,9 @@ +{ + "$schema": "../../../../node_modules/@angular-devkit/schematics/collection-schema.json", + "schematics": { + "ng-add": { + "description": "Add @angular-material-extensions/select-country to the project.", + "factory": "./ng-add/index" + } + } +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/ast-utils.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/ast-utils.ts new file mode 100755 index 0000000..3d11745 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/ast-utils.ts @@ -0,0 +1,218 @@ +import { + insertImport as originalInsertImport, + findNodes as originalFindNodes, + findNode as originalFindNode, + getSourceNodes as originalGetSourceNodes, + insertAfterLastOccurrence as originalInsertAfterLastOccurrence, + getContentOfKeyLiteral as originalGetContentOfKeyLiteral, + getFirstNgModuleName as originalGetFirstNgModuleName, + getDecoratorMetadata as originalGetDecoratorMetadata, + getMetadataField as originalGetMetadataField, + getRouterModuleDeclaration as originalGetRouterModuleDeclaration, + addSymbolToNgModuleMetadata as originalAddSymbolToNgModuleMetadata, + addDeclarationToModule as originalAddDeclarationToModule, + addImportToModule as originalAddImportToModule, + addProviderToModule as originalAddProviderToModule, + addExportToModule as originalAddExportToModule, + addBootstrapToModule as originalAddBootstrapToModule, + addEntryComponentToModule as originalAddEntryComponentToModule, + addRouteDeclarationToModule as originalAddRouteDeclarationToModule, + isImported as originalIsImported +} from '@schematics/angular/utility/ast-utils'; +import * as ts from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript'; + +import { Change } from './change'; + +/** + * Add Import `import { symbolName } from fileName` if the import doesn't exit + * already. Assumes fileToEdit can be resolved and accessed. + * @param fileToEdit (file we want to add import to) + * @param symbolName (item to import) + * @param fileName (path to the file) + * @param isDefault (if true, import follows style for importing default exports) + * @return Change + */ +export function insertImport( + source: ts.SourceFile, + fileToEdit: string, + symbolName: string, + fileName: string, + isDefault = false +): Change { + return originalInsertImport(source, fileToEdit, symbolName, fileName, isDefault); +} + +/** + * Find all nodes from the AST in the subtree of node of SyntaxKind kind. + * @param node + * @param kind + * @param max The maximum number of items to return. + * @param recursive Continue looking for nodes of kind recursive until end + * the last child even when node of kind has been found. + * @return all nodes of kind, or [] if none is found + */ +export function findNodes(node: ts.Node, kind: ts.SyntaxKind, max = Infinity, recursive = false): ts.Node[] { + return originalFindNodes(node, kind, max, recursive); +} + +/** + * Get all the nodes from a source. + * @param sourceFile The source file object. + * @returns {Observable} An observable of all the nodes in the source. + */ +export function getSourceNodes(sourceFile: ts.SourceFile): ts.Node[] { + return originalGetSourceNodes(sourceFile); +} + +export function findNode(node: ts.Node, kind: ts.SyntaxKind, text: string): ts.Node | null { + return originalFindNode(node, kind, text); +} + +/** + * Insert `toInsert` after the last occurence of `ts.SyntaxKind[nodes[i].kind]` + * or after the last of occurence of `syntaxKind` if the last occurence is a sub child + * of ts.SyntaxKind[nodes[i].kind] and save the changes in file. + * + * @param nodes insert after the last occurence of nodes + * @param toInsert string to insert + * @param file file to insert changes into + * @param fallbackPos position to insert if toInsert happens to be the first occurence + * @param syntaxKind the ts.SyntaxKind of the subchildren to insert after + * @return Change instance + * @throw Error if toInsert is first occurence but fall back is not set + */ +export function insertAfterLastOccurrence( + nodes: ts.Node[], + toInsert: string, + file: string, + fallbackPos: number, + syntaxKind?: ts.SyntaxKind +): Change { + return originalInsertAfterLastOccurrence(nodes, toInsert, file, fallbackPos, syntaxKind); +} + +export function getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): string | null { + return originalGetContentOfKeyLiteral(_source, node); +} + +export function getDecoratorMetadata(source: ts.SourceFile, identifier: string, module: string): ts.Node[] { + return originalGetDecoratorMetadata(source, identifier, module); +} + +/** + * Given a source file with @NgModule class(es), find the name of the first @NgModule class. + * + * @param source source file containing one or more @NgModule + * @returns the name of the first @NgModule, or `undefined` if none is found + */ +export function getFirstNgModuleName(source: ts.SourceFile): string | undefined { + return originalGetFirstNgModuleName(source); +} + +export function getMetadataField(node: ts.ObjectLiteralExpression, metadataField: string): ts.ObjectLiteralElement[] { + return originalGetMetadataField(node, metadataField); +} + +export function addSymbolToNgModuleMetadata( + source: ts.SourceFile, + ngModulePath: string, + metadataField: string, + symbolName: string, + importPath: string | null = null +): Change[] { + return originalAddSymbolToNgModuleMetadata(source, ngModulePath, metadataField, symbolName, importPath); +} + +/** + * Custom function to insert a declaration (component, pipe, directive) + * into NgModule declarations. It also imports the component. + */ +export function addDeclarationToModule( + source: ts.SourceFile, + modulePath: string, + classifiedName: string, + importPath: string +): Change[] { + return originalAddDeclarationToModule(source, modulePath, classifiedName, importPath); +} + +/** + * Custom function to insert an NgModule into NgModule imports. It also imports the module. + */ +export function addImportToModule( + source: ts.SourceFile, + modulePath: string, + classifiedName: string, + importPath: string +): Change[] { + return originalAddImportToModule(source, modulePath, classifiedName, importPath); +} + +/** + * Custom function to insert a provider into NgModule. It also imports it. + */ +export function addProviderToModule( + source: ts.SourceFile, + modulePath: string, + classifiedName: string, + importPath: string +): Change[] { + return originalAddProviderToModule(source, modulePath, classifiedName, importPath); +} + +/** + * Custom function to insert an export into NgModule. It also imports it. + */ +export function addExportToModule( + source: ts.SourceFile, + modulePath: string, + classifiedName: string, + importPath: string +): Change[] { + return originalAddExportToModule(source, modulePath, classifiedName, importPath); +} + +/** + * Custom function to insert an export into NgModule. It also imports it. + */ +export function addBootstrapToModule( + source: ts.SourceFile, + modulePath: string, + classifiedName: string, + importPath: string +): Change[] { + return originalAddBootstrapToModule(source, modulePath, classifiedName, importPath); +} + +/** + * Custom function to insert an entryComponent into NgModule. It also imports it. + */ +export function addEntryComponentToModule( + source: ts.SourceFile, + modulePath: string, + classifiedName: string, + importPath: string +): Change[] { + return originalAddEntryComponentToModule(source, modulePath, classifiedName, importPath); +} + +/** + * Determine if an import already exists. + */ +export function isImported(source: ts.SourceFile, classifiedName: string, importPath: string): boolean { + return originalIsImported(source, classifiedName, importPath); +} + +/** + * Returns the RouterModule declaration from NgModule metadata, if any. + */ +export function getRouterModuleDeclaration(source: ts.SourceFile): ts.Expression | undefined { + return originalGetRouterModuleDeclaration(source); +} + +/** + * Adds a new route declaration to a router module (i.e. has a RouterModule declaration) + */ +export function addRouteDeclarationToModule(source: ts.SourceFile, fileToAdd: string, routeLiteral: string): Change { + return originalAddRouteDeclarationToModule(source, fileToAdd, routeLiteral); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/change.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/change.ts new file mode 100755 index 0000000..31c6e21 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/change.ts @@ -0,0 +1,32 @@ +import { + Host as OriginalHost, + Change as OriginalChange, + NoopChange as OriginalNoopChange, + InsertChange as OriginalInsertChange, + RemoveChange as OriginalRemoveChange, + ReplaceChange as OriginalReplaceChange +} from '@schematics/angular/utility/change'; + +export interface Host extends OriginalHost {} + +export interface Change extends OriginalChange {} + +/** + * An operation that does nothing. + */ +export class NoopChange extends OriginalNoopChange {} + +/** + * Will add text to the source code. + */ +export class InsertChange extends OriginalInsertChange {} + +/** + * Will remove text from the source code. + */ +export class RemoveChange extends OriginalRemoveChange {} + +/** + * Will replace text from the source code. + */ +export class ReplaceChange extends OriginalReplaceChange {} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/component-schema.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/component-schema.ts new file mode 100644 index 0000000..5d03f76 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/component-schema.ts @@ -0,0 +1,78 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export interface Schema { + /** + * The path to create the component. + */ + path?: string; + /** + * The name of the project. + */ + project?: string; + /** + * The name of the component. + */ + name: string; + /** + * Specifies if the style will be in the ts file. + */ + inlineStyle?: boolean; + /** + * Specifies if the template will be in the ts file. + */ + inlineTemplate?: boolean; + /** + * Specifies the view encapsulation strategy. + */ + viewEncapsulation?: 'Emulated' | 'Native' | 'None'; + /** + * Specifies the change detection strategy. + */ + changeDetection?: 'Default' | 'OnPush'; + /** + * The prefix to apply to generated selectors. + */ + prefix?: string; + /** + * The file extension to be used for style files. + */ + styleext?: string; + /** + * Specifies if a spec file is generated. + */ + spec?: boolean; + /** + * Flag to indicate if a dir is created. + */ + flat?: boolean; + /** + * Flag to skip the module import. + */ + skipImport?: boolean; + /** + * The selector to use for the component. + */ + selector?: string; + /** + * Allows specification of the declaring module. + */ + module?: string; + /** + * Specifies if declaring module exports the component. + */ + export?: boolean; + /** + * Specifies if the component is an entry component of declaring module. + */ + entryComponent?: boolean; + /** + * Specifies whether to apply lint fixes after generating the component. + */ + lintFix?: boolean; +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/dependencies.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/dependencies.ts new file mode 100755 index 0000000..73d2bcf --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/dependencies.ts @@ -0,0 +1,28 @@ +import { Tree } from '@angular-devkit/schematics'; +import { + NodeDependency as OriginalNodeDependency, + addPackageJsonDependency as originalAddPackageJsonDependency, + getPackageJsonDependency as originalGetPackageJsonDependency, + removePackageJsonDependency as originalRemovePackageJsonDependency +} from '@schematics/angular/utility/dependencies'; + +export enum NodeDependencyType { + Default = 'dependencies', + Dev = 'devDependencies', + Peer = 'peerDependencies', + Optional = 'optionalDependencies' +} + +export interface NodeDependency extends OriginalNodeDependency {} + +export function addPackageJsonDependency(tree: Tree, dependency: NodeDependency): void { + return originalAddPackageJsonDependency(tree, dependency); +} + +export function removePackageJsonDependency(tree: Tree, name: string): void { + return originalRemovePackageJsonDependency(tree, name); +} + +export function getPackageJsonDependency(tree: Tree, name: string): NodeDependency | null { + return originalGetPackageJsonDependency(tree, name); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/find-module.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/find-module.ts new file mode 100755 index 0000000..94b1358 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/find-module.ts @@ -0,0 +1,42 @@ +import { Path } from '@angular-devkit/core'; +import { Tree } from '@angular-devkit/schematics'; + +import { + ModuleOptions as OriginalModuleOptions, + findModuleFromOptions as originalFindModuleFromOptions, + findModule as originalFindModule, + buildRelativePath as originalBuildRelativePath, + MODULE_EXT as ORIGINAL_MODULE_EXT, + ROUTING_MODULE_EXT as ORIGINAL_ROUTING_MODULE_EXT +} from '@schematics/angular/utility/find-module'; + +export interface ModuleOptions extends OriginalModuleOptions {} + +/** + * Find the module referred by a set of options passed to the schematics. + */ +export function findModuleFromOptions(host: Tree, options: ModuleOptions): Path | undefined { + return originalFindModuleFromOptions(host, options); +} + +/** + * Function to find the "closest" module to a generated file's path. + */ +export function findModule( + host: Tree, + generateDir: string, + moduleExt = MODULE_EXT, + routingModuleExt = ROUTING_MODULE_EXT +): Path { + return originalFindModule(host, generateDir, moduleExt, routingModuleExt); +} + +/** + * Build a relative path from one file path to another file path. + */ +export function buildRelativePath(from: string, to: string): string { + return originalBuildRelativePath(from, to); +} + +export const MODULE_EXT = ORIGINAL_MODULE_EXT; +export const ROUTING_MODULE_EXT = ORIGINAL_ROUTING_MODULE_EXT; diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/index.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/index.ts new file mode 100644 index 0000000..9c71f3c --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/index.ts @@ -0,0 +1,13 @@ +export * from './ast-utils'; +export * from './change'; +export * from './component-schema'; +export * from './dependencies'; +export * from './find-module'; +export * from './json-utils'; +export * from './latest-versions'; +export * from './ng-ast-utils'; +export * from './parse-name'; +export * from './paths'; +export * from './project'; +export * from './validation'; +export * from './workspace-models'; diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/json-utils.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/json-utils.ts new file mode 100755 index 0000000..2910031 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/json-utils.ts @@ -0,0 +1,42 @@ +import { JsonAstArray, JsonAstNode, JsonAstObject, JsonValue } from '@angular-devkit/core'; +import { UpdateRecorder } from '@angular-devkit/schematics'; + +import { + appendPropertyInAstObject as originalAppendPropertyInAstObject, + removePropertyInAstObject as originalRemovePropertyInAstObject, + insertPropertyInAstObjectInOrder as originalInsertPropertyInAstObjectInOrder, + appendValueInAstArray as originalAppendValueInAstArray, + findPropertyInAstObject as originalFindPropertyInAstObject +} from '@schematics/angular/utility/json-utils'; + +export function appendPropertyInAstObject( + recorder: UpdateRecorder, + node: JsonAstObject, + propertyName: string, + value: JsonValue, + indent: number +) { + return originalAppendPropertyInAstObject(recorder, node, propertyName, value, indent); +} + +export function insertPropertyInAstObjectInOrder( + recorder: UpdateRecorder, + node: JsonAstObject, + propertyName: string, + value: JsonValue, + indent: number +) { + return originalInsertPropertyInAstObjectInOrder(recorder, node, propertyName, value, indent); +} + +export function removePropertyInAstObject(recorder: UpdateRecorder, node: JsonAstObject, propertyName: string) { + return originalRemovePropertyInAstObject(recorder, node, propertyName); +} + +export function appendValueInAstArray(recorder: UpdateRecorder, node: JsonAstArray, value: JsonValue, indent = 4) { + return originalAppendValueInAstArray(recorder, node, value, indent); +} + +export function findPropertyInAstObject(node: JsonAstObject, propertyName: string): JsonAstNode | null { + return originalFindPropertyInAstObject(node, propertyName); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/latest-versions.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/latest-versions.ts new file mode 100755 index 0000000..b2c2ece --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/latest-versions.ts @@ -0,0 +1,3 @@ +import { latestVersions as originalLatestVersions } from '@schematics/angular/utility/latest-versions'; + +export const latestVersions = originalLatestVersions; diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/ng-ast-utils.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/ng-ast-utils.ts new file mode 100755 index 0000000..bb3575e --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/ng-ast-utils.ts @@ -0,0 +1,19 @@ +import { Tree } from '@angular-devkit/schematics'; +import { + findBootstrapModuleCall as originalFindBootstrapModuleCall, + findBootstrapModulePath as originalFindBootstrapModulePath, + getAppModulePath as originalGetAppModulePath +} from '@schematics/angular/utility/ng-ast-utils'; +import * as ts from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript'; + +export function findBootstrapModuleCall(host: Tree, mainPath: string): ts.CallExpression | null { + return originalFindBootstrapModuleCall(host, mainPath); +} + +export function findBootstrapModulePath(host: Tree, mainPath: string): string { + return originalFindBootstrapModulePath(host, mainPath); +} + +export function getAppModulePath(host: Tree, mainPath: string): string { + return originalGetAppModulePath(host, mainPath); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/parse-name.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/parse-name.ts new file mode 100755 index 0000000..086c94b --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/parse-name.ts @@ -0,0 +1,7 @@ +import { Location as OriginalLocation, parseName as originalParseName } from '@schematics/angular/utility/parse-name'; + +export interface Location extends OriginalLocation {} + +export function parseName(path: string, name: string): Location { + return originalParseName(path, name); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/paths.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/paths.ts new file mode 100644 index 0000000..d278100 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/paths.ts @@ -0,0 +1,5 @@ +import { relativePathToWorkspaceRoot as originalRelativePathToWorkspaceRoot } from '@schematics/angular/utility/paths'; + +export function relativePathToWorkspaceRoot(projectRoot: string | undefined): string { + return originalRelativePathToWorkspaceRoot(projectRoot); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/project.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/project.ts new file mode 100755 index 0000000..18eb942 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/project.ts @@ -0,0 +1,31 @@ +import { Tree } from '@angular-devkit/schematics'; +import { + buildDefaultPath as originalBuildDefaultPath, + getProject as originalGetProject, + isWorkspaceSchema as originalIsWorkspaceSchema, + isWorkspaceProject as originalIsWorkspaceProject +} from '@schematics/angular/utility/project'; +import { ProjectType, WorkspaceProject, WorkspaceSchema } from '@schematics/angular/utility/workspace-models'; + +/** + * Build a default project path for generating. + * @param project The project to build the path for. + */ +export function buildDefaultPath(project: WorkspaceProject): string { + return originalBuildDefaultPath(project); +} + +export function getProject( + workspaceOrHost: WorkspaceSchema | Tree, + projectName: string +): WorkspaceProject { + return originalGetProject(workspaceOrHost, projectName); +} + +export function isWorkspaceSchema(workspace: any): workspace is WorkspaceSchema { + return originalIsWorkspaceSchema(workspace); +} + +export function isWorkspaceProject(project: any): project is WorkspaceProject { + return originalIsWorkspaceProject(project); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/validation.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/validation.ts new file mode 100755 index 0000000..1b214a5 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/validation.ts @@ -0,0 +1,22 @@ +import { + htmlSelectorRe as originalHtmlSelectorRe, + validateName as originalValidateName, + validateHtmlSelector as originalValidateHtmlSelector, + validateProjectName as originalValidateProjectName +} from '@schematics/angular/utility/validation'; + +export function validateName(name: string): void { + return originalValidateName(name); +} + +// Must start with a letter, and must contain only alphanumeric characters or dashes. +// When adding a dash the segment after the dash must also start with a letter. +export const htmlSelectorRe = originalHtmlSelectorRe; + +export function validateHtmlSelector(selector: string): void { + return originalValidateHtmlSelector(selector); +} + +export function validateProjectName(projectName: string) { + return originalValidateProjectName(projectName); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/angular/workspace-models.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/workspace-models.ts new file mode 100644 index 0000000..7a4c61b --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/angular/workspace-models.ts @@ -0,0 +1,157 @@ +import { experimental } from '@angular-devkit/core'; + +export enum ProjectType { + Application = 'application', + Library = 'library' +} + +export enum Builders { + AppShell = '@angular-devkit/build-angular:app-shell', + Server = '@angular-devkit/build-angular:server', + Browser = '@angular-devkit/build-angular:browser', + Karma = '@angular-devkit/build-angular:karma', + TsLint = '@angular-devkit/build-angular:tslint', + NgPackagr = '@angular-devkit/build-ng-packagr:build', + DevServer = '@angular-devkit/build-angular:dev-server', + ExtractI18n = '@angular-devkit/build-angular:extract-i18n', + Protractor = '@angular-devkit/build-angular:protractor' +} + +export interface FileReplacements { + replace: string; + with: string; +} + +export interface BrowserBuilderBaseOptions { + main: string; + tsConfig: string; + fileReplacements?: FileReplacements[]; + outputPath?: string; + index?: string; + polyfills: string; + assets?: (object | string)[]; + styles?: (object | string)[]; + scripts?: (object | string)[]; + sourceMap?: boolean; +} + +export interface BrowserBuilderOptions extends BrowserBuilderBaseOptions { + serviceWorker?: boolean; + optimization?: boolean; + outputHashing?: 'all'; + resourcesOutputPath?: string; + extractCss?: boolean; + namedChunks?: boolean; + aot?: boolean; + extractLicenses?: boolean; + vendorChunk?: boolean; + buildOptimizer?: boolean; + ngswConfigPath?: string; + budgets?: { + type: string; + maximumWarning?: string; + maximumError?: string; + }[]; + es5BrowserSupport?: boolean; + webWorkerTsConfig?: string; +} + +export interface ServeBuilderOptions { + browserTarget: string; +} +export interface LibraryBuilderOptions { + tsConfig: string; + project: string; +} + +export interface ServerBuilderOptions { + outputPath: string; + tsConfig: string; + main: string; + fileReplacements?: FileReplacements[]; + optimization?: { + scripts?: boolean; + styles?: boolean; + }; + sourceMap?: boolean; +} + +export interface AppShellBuilderOptions { + browserTarget: string; + serverTarget: string; + route: string; +} + +export interface TestBuilderOptions extends Partial { + karmaConfig: string; +} + +export interface LintBuilderOptions { + tsConfig: string[] | string; + exclude?: string[]; +} + +export interface ExtractI18nOptions { + browserTarget: string; +} + +export interface E2EOptions { + protractorConfig: string; + devServerTarget: string; +} + +export interface BuilderTarget { + builder: TBuilder; + options: TOptions; + configurations?: { + production: Partial; + [key: string]: Partial; + }; +} + +export type LibraryBuilderTarget = BuilderTarget; +export type BrowserBuilderTarget = BuilderTarget; +export type ServerBuilderTarget = BuilderTarget; +export type AppShellBuilderTarget = BuilderTarget; +export type LintBuilderTarget = BuilderTarget; +export type TestBuilderTarget = BuilderTarget; +export type ServeBuilderTarget = BuilderTarget; +export type ExtractI18nBuilderTarget = BuilderTarget; +export type E2EBuilderTarget = BuilderTarget; + +export interface WorkspaceSchema extends experimental.workspace.WorkspaceSchema { + projects: { + [key: string]: WorkspaceProject; + }; +} + +export interface WorkspaceProject + extends experimental.workspace.WorkspaceProject { + /** + * Project type. + */ + projectType: ProjectType; + + /** + * Tool options. + */ + architect?: WorkspaceTargets; + /** + * Tool options. + */ + targets?: WorkspaceTargets; +} + +export interface WorkspaceTargets { + build?: TProjectType extends ProjectType.Library ? LibraryBuilderTarget : BrowserBuilderTarget; + server?: ServerBuilderTarget; + lint?: LintBuilderTarget; + test?: TestBuilderTarget; + serve?: ServeBuilderTarget; + e2e?: E2EBuilderTarget; + 'app-shell'?: AppShellBuilderTarget; + 'extract-i18n'?: ExtractI18nBuilderTarget; + // TODO(hans): change this any to unknown when google3 supports TypeScript 3.0. + // tslint:disable-next-line:no-any + [key: string]: any; +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/index.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/index.ts new file mode 100644 index 0000000..fde1781 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/index.ts @@ -0,0 +1,2 @@ +export * from './angular/index'; +export * from './material/index'; diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/material/ast/ng-module-imports.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/material/ast/ng-module-imports.ts new file mode 100644 index 0000000..154aa42 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/material/ast/ng-module-imports.ts @@ -0,0 +1,9 @@ +import { Tree } from '@angular-devkit/schematics'; +import { hasNgModuleImport as originalHasNgModuleImport } from '@angular/cdk/schematics'; + +/** + * Whether the Angular module in the given path imports the specified module class name. + */ +export function hasNgModuleImport(tree: Tree, modulePath: string, className: string): boolean { + return originalHasNgModuleImport(tree, modulePath, className); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/material/build-component.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/material/build-component.ts new file mode 100644 index 0000000..f0cc62a --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/material/build-component.ts @@ -0,0 +1,15 @@ +import { Rule } from '@angular-devkit/schematics'; +import { Schema as ComponentOptions } from '@schematics/angular/component/schema'; +import { buildComponent as originalBuildComponent } from '@angular/cdk/schematics'; + +/** + * Rule that copies and interpolates the files that belong to this schematic context. Additionally + * a list of file paths can be passed to this rule in order to expose them inside the EJS + * template context. + * + * This allows inlining the external template or stylesheet files in EJS without having + * to manually duplicate the file content. + */ +export function buildComponent(options: ComponentOptions, additionalFiles: { [key: string]: string } = {}): Rule { + return originalBuildComponent(options, additionalFiles); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/material/get-project.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/material/get-project.ts new file mode 100644 index 0000000..d69bb0b --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/material/get-project.ts @@ -0,0 +1,10 @@ +import { getProjectFromWorkspace as originalGetProjectFromWorkspace } from '@angular/cdk/schematics'; +import { WorkspaceSchema, WorkspaceProject } from '@angular-devkit/core/src/experimental/workspace'; + +/** + * 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 { + return originalGetProjectFromWorkspace(workspace, projectName); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/material/index.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/material/index.ts new file mode 100644 index 0000000..08f3eeb --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/material/index.ts @@ -0,0 +1,4 @@ +export * from './ast/ng-module-imports'; +export * from './build-component'; +export * from './get-project'; +export * from './package-config'; diff --git a/projects/angular-material-extensions/select-icon/schematics/helpers/material/package-config.ts b/projects/angular-material-extensions/select-icon/schematics/helpers/material/package-config.ts new file mode 100644 index 0000000..d51a930 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/helpers/material/package-config.ts @@ -0,0 +1,7 @@ +import { Tree } from '@angular-devkit/schematics'; +import { addPackageToPackageJson as originalAddPackageToPackageJson } from '@angular/cdk/schematics/ng-add/package-config'; + +/** Adds a package to the package.json in the given host tree. */ +export function addPackageToPackageJson(host: Tree, pkg: string, version: string): Tree { + return originalAddPackageToPackageJson(host, pkg, version); +} diff --git a/projects/angular-material-extensions/select-icon/schematics/ng-add/index.ts b/projects/angular-material-extensions/select-icon/schematics/ng-add/index.ts new file mode 100755 index 0000000..bbc8bb9 --- /dev/null +++ b/projects/angular-material-extensions/select-icon/schematics/ng-add/index.ts @@ -0,0 +1,87 @@ +import { chain, noop, Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; +import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; +import { addModuleImportToRootModule, getProjectFromWorkspace } from '@angular/cdk/schematics'; +import { getWorkspace } from '@schematics/angular/utility/config'; +import { addPackageJsonDependency, NodeDependency, NodeDependencyType } from '../helpers'; + +/** Loads the full version from the given Angular package gracefully. */ +function loadPackageVersionGracefully(): string | null { + try { + console.log('@angular-material-extensions/select-icon version = ', require(`../../package.json`).version); + return require(`../../package.json`).version; + } catch { + return null; + } +} + +// You don't have to export the function as default. You can also have more than one rule factory +// per file. +export function addPackageJsonDependencies(): Rule { + return (host: Tree, context: SchematicContext) => { + + const dependencies: NodeDependency[] = [ + { + type: NodeDependencyType.Default, version: loadPackageVersionGracefully() + || '1.3.0', name: '@angular-material-extensions/select-icon' + }, + { type: NodeDependencyType.Default, version: '^1.2.6', name: 'svg-icon-flags' } + ]; + + dependencies.forEach(dependency => { + addPackageJsonDependency(host, dependency); + context.logger.log('info', `✅️ Added "${dependency.name}" into ${dependency.type}`); + }); + + return host; + }; +} + +export function installPackageJsonDependencies(): Rule { + return (host: Tree, context: SchematicContext) => { + context.addTask(new NodePackageInstallTask()); + context.logger.log('info', `🔍 Installing packages...`); + + return host; + }; +} + +export function addModuleToImports(options: any): Rule { + return (host: Tree, context: SchematicContext) => { + const workspace = getWorkspace(host); + const project = getProjectFromWorkspace( + workspace, + // Takes the first project in case it's not provided by CLI + options.project ? options.project : Object.keys(workspace.projects)[0] + ); + + const moduleName = `MatSelectIconModule`; + + addModuleImportToRootModule(host, moduleName, '@angular-material-extensions/select-icon', project); + context.logger.log('info', `✅️ "${moduleName}" is imported`); + + return host; + }; +} + +/** Gets the version of the specified package by looking at the package.json in the given tree. */ +export function getPackageVersionFromPackageJson(tree: Tree, name: string): string | null { + if (!tree.exists('package.json')) { + return null; + } + + // tslint:disable-next-line:no-non-null-assertion + const packageJson = JSON.parse(tree.read('package.json')!.toString('utf8')); + + if (packageJson.dependencies && packageJson.dependencies[name]) { + return packageJson.dependencies[name]; + } + + return null; +} + +export default function(options: any): Rule { + return chain([ + options && options.skipPackageJson ? noop() : addPackageJsonDependencies(), + options && options.skipPackageJson ? noop() : installPackageJsonDependencies(), + options && options.skipModuleImport ? noop() : addModuleToImports(options)]); +} diff --git a/projects/angular-material-extensions/select-icon/tsconfig.schematics.json b/projects/angular-material-extensions/select-icon/tsconfig.schematics.json new file mode 100644 index 0000000..b29076e --- /dev/null +++ b/projects/angular-material-extensions/select-icon/tsconfig.schematics.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "baseUrl": "tsconfig", + "lib": [ + "es2018", + "dom" + ], + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "noEmitOnError": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitThis": true, + "noUnusedParameters": true, + "noUnusedLocals": true, + "rootDir": "schematics", + "outDir": "../../../dist/angular-material-extensions/select-icon/schematics", + "skipDefaultLibCheck": true, + "skipLibCheck": true, + "sourceMap": true, + "strictNullChecks": true, + "target": "es6", + "types": [ + "jasmine", + "node" + ] + }, + "include": [ + "schematics/**/*" + ], + "exclude": [ + "schematics/*/files/**/*" + ] +}