mirror of https://github.com/abpframework/abp.git
committed by
GitHub
81 changed files with 1423 additions and 1224 deletions
@ -1,5 +1,7 @@ |
|||||
{ |
{ |
||||
"culture": "tr", |
"culture": "tr", |
||||
"texts": { |
"texts": { |
||||
|
"AbpTitle": "ABP Framework - Açık Kaynak Web Uygulama Çerçevesi", |
||||
|
"AbpDescription": "ABP, AspNet Core tabanlı web uygulaması geliştirmeye odaklanan açık kaynaklı bir uygulama çerçevesidir. Kendinizi tekrar etmeyin, kendi iş kodunuza odaklanın." |
||||
} |
} |
||||
} |
} |
||||
@ -1,6 +1,6 @@ |
|||||
{ |
{ |
||||
"culture": "tr", |
"culture": "tr", |
||||
"texts": { |
"texts": { |
||||
|
"Volo.Abp.Http.DynamicProxying:10001": "Verilerle ilgili iş istisnası: {0}" |
||||
} |
} |
||||
} |
} |
||||
@ -1,6 +1,6 @@ |
|||||
{ |
{ |
||||
"culture": "tr", |
"culture": "tr", |
||||
"texts": { |
"texts": { |
||||
|
"SeeYou": "Görüşürüz" |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
{ |
||||
|
"extends": "../../.eslintrc.json", |
||||
|
"ignorePatterns": [ |
||||
|
"!**/*" |
||||
|
], |
||||
|
"overrides": [ |
||||
|
{ |
||||
|
"files": [ |
||||
|
"*.ts" |
||||
|
], |
||||
|
"parserOptions": { |
||||
|
"project": [ |
||||
|
"projects/<%= kebab(libraryName) %>/tsconfig.lib.json", |
||||
|
"projects/<%= kebab(libraryName) %>/tsconfig.spec.json" |
||||
|
], |
||||
|
"createDefaultProgram": true |
||||
|
}, |
||||
|
"rules": { |
||||
|
"@angular-eslint/directive-selector": [ |
||||
|
"error", |
||||
|
{ |
||||
|
"type": "attribute", |
||||
|
"prefix": "lib", |
||||
|
"style": "camelCase" |
||||
|
} |
||||
|
], |
||||
|
"@angular-eslint/component-selector": [ |
||||
|
"error", |
||||
|
{ |
||||
|
"type": "element", |
||||
|
"prefix": "lib", |
||||
|
"style": "kebab-case" |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"files": [ |
||||
|
"*.html" |
||||
|
], |
||||
|
"rules": {} |
||||
|
} |
||||
|
] |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../dist/<%= kebab(libraryName) %>/config", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
import { ModuleWithProviders, NgModule } from '@angular/core'; |
||||
|
import { <%= macro(libraryName) %>_ROUTE_PROVIDERS } from './providers/route.provider'; |
||||
|
|
||||
|
@NgModule() |
||||
|
export class <%= pascal(libraryName) %>ConfigModule { |
||||
|
static forRoot(): ModuleWithProviders<<%= pascal(libraryName) %>ConfigModule> { |
||||
|
return { |
||||
|
ngModule: <%= pascal(libraryName) %>ConfigModule, |
||||
|
providers: [<%= macro(libraryName) %>_ROUTE_PROVIDERS], |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './route-names'; |
||||
@ -0,0 +1,3 @@ |
|||||
|
export const enum e<%= pascal(libraryName) %>RouteNames { |
||||
|
<%= pascal(libraryName) %> = '<%= pascal(libraryName) %>', |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './route.provider'; |
||||
@ -0,0 +1,26 @@ |
|||||
|
import { eLayoutType, RoutesService } from '@abp/ng.core'; |
||||
|
import { APP_INITIALIZER } from '@angular/core'; |
||||
|
import { e<%= pascal(libraryName) %>RouteNames } from '../enums/route-names'; |
||||
|
|
||||
|
export const <%= macro(libraryName) %>_ROUTE_PROVIDERS = [ |
||||
|
{ |
||||
|
provide: APP_INITIALIZER, |
||||
|
useFactory: configureRoutes, |
||||
|
deps: [RoutesService], |
||||
|
multi: true, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export function configureRoutes(routesService: RoutesService) { |
||||
|
return () => { |
||||
|
routesService.add([ |
||||
|
{ |
||||
|
path: '/<%= kebab(libraryName) %>', |
||||
|
name: e<%= pascal(libraryName) %>RouteNames.<%= pascal(libraryName) %>, |
||||
|
iconClass: 'fas fa-book', |
||||
|
layout: eLayoutType.application, |
||||
|
order: 3, |
||||
|
}, |
||||
|
]); |
||||
|
}; |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
export * from './enums'; |
||||
|
export * from './<%= kebab(libraryName) %>-config.module'; |
||||
|
export * from './providers'; |
||||
@ -0,0 +1,44 @@ |
|||||
|
// Karma configuration file, see link for more information |
||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html |
||||
|
|
||||
|
module.exports = function (config) { |
||||
|
config.set({ |
||||
|
basePath: '', |
||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'], |
||||
|
plugins: [ |
||||
|
require('karma-jasmine'), |
||||
|
require('karma-chrome-launcher'), |
||||
|
require('karma-jasmine-html-reporter'), |
||||
|
require('karma-coverage'), |
||||
|
require('@angular-devkit/build-angular/plugins/karma') |
||||
|
], |
||||
|
client: { |
||||
|
jasmine: { |
||||
|
// you can add configuration options for Jasmine here |
||||
|
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html |
||||
|
// for example, you can disable the random execution with `random: false` |
||||
|
// or set a specific seed with `seed: 4321` |
||||
|
}, |
||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser |
||||
|
}, |
||||
|
jasmineHtmlReporter: { |
||||
|
suppressAll: true // removes the duplicated traces |
||||
|
}, |
||||
|
coverageReporter: { |
||||
|
dir: require('path').join(__dirname, '../../coverage/my-project-name'), |
||||
|
subdir: '.', |
||||
|
reporters: [ |
||||
|
{ type: 'html' }, |
||||
|
{ type: 'text-summary' } |
||||
|
] |
||||
|
}, |
||||
|
reporters: ['progress', 'kjhtml'], |
||||
|
port: 9876, |
||||
|
colors: true, |
||||
|
logLevel: config.LOG_INFO, |
||||
|
autoWatch: true, |
||||
|
browsers: ['Chrome'], |
||||
|
singleRun: false, |
||||
|
restartOnFileChange: true |
||||
|
}); |
||||
|
}; |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../dist/<%= kebab(libraryName) %>", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
{ |
||||
|
"name": "@<%= kebab(libraryName) %>/<%= kebab(libraryName) %>", |
||||
|
"version": "0.0.1", |
||||
|
"peerDependencies": { |
||||
|
"@abp/ng.core": "<%= abpVersion %>", |
||||
|
"@abp/ng.theme.shared": "<%= abpVersion %>" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"tslib": "^2.1.0" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
import { NgModule } from '@angular/core'; |
||||
|
import { DynamicLayoutComponent } from '@abp/ng.core'; |
||||
|
import { Routes, RouterModule } from '@angular/router'; |
||||
|
|
||||
|
const routes: Routes = [ |
||||
|
{ |
||||
|
path: '', |
||||
|
pathMatch: 'full', |
||||
|
component: DynamicLayoutComponent, |
||||
|
children: [], |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
@NgModule({ |
||||
|
imports: [RouterModule.forChild(routes)], |
||||
|
exports: [RouterModule], |
||||
|
}) |
||||
|
export class <%= pascal(libraryName) %>RoutingModule {} |
||||
@ -0,0 +1,22 @@ |
|||||
|
import { NgModule, NgModuleFactory, ModuleWithProviders } from '@angular/core'; |
||||
|
import { CoreModule, LazyModuleFactory } from '@abp/ng.core'; |
||||
|
import { ThemeSharedModule } from '@abp/ng.theme.shared'; |
||||
|
import { <%= pascal(libraryName) %>RoutingModule } from './<%= kebab(libraryName) %>-routing.module'; |
||||
|
|
||||
|
@NgModule({ |
||||
|
declarations: [], |
||||
|
imports: [CoreModule, ThemeSharedModule, <%= pascal(libraryName) %>RoutingModule], |
||||
|
exports: [], |
||||
|
}) |
||||
|
export class <%= pascal(libraryName) %>Module { |
||||
|
static forChild(): ModuleWithProviders<<%= pascal(libraryName) %>Module> { |
||||
|
return { |
||||
|
ngModule: <%= pascal(libraryName) %>Module, |
||||
|
providers: [], |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
static forLazy(): NgModuleFactory<<%= pascal(libraryName) %>Module> { |
||||
|
return new LazyModuleFactory(<%= pascal(libraryName) %>Module.forChild()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,4 @@ |
|||||
|
/* |
||||
|
* Public API Surface of my-project-name |
||||
|
*/ |
||||
|
export * from './lib/<%= kebab(libraryName) %>.module'; |
||||
@ -0,0 +1,26 @@ |
|||||
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files |
||||
|
|
||||
|
import 'zone.js'; |
||||
|
import 'zone.js/testing'; |
||||
|
import { getTestBed } from '@angular/core/testing'; |
||||
|
import { |
||||
|
BrowserDynamicTestingModule, |
||||
|
platformBrowserDynamicTesting |
||||
|
} from '@angular/platform-browser-dynamic/testing'; |
||||
|
|
||||
|
declare const require: { |
||||
|
context(path: string, deep?: boolean, filter?: RegExp): { |
||||
|
keys(): string[]; |
||||
|
<T>(id: string): T; |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
// First, initialize the Angular testing environment. |
||||
|
getTestBed().initTestEnvironment( |
||||
|
BrowserDynamicTestingModule, |
||||
|
platformBrowserDynamicTesting() |
||||
|
); |
||||
|
// Then we find all the tests. |
||||
|
const context = require.context('./', true, /\.spec\.ts$/); |
||||
|
// And load the modules. |
||||
|
context.keys().map(context); |
||||
@ -0,0 +1,20 @@ |
|||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
||||
|
{ |
||||
|
"extends": "../../tsconfig.json", |
||||
|
"compilerOptions": { |
||||
|
"outDir": "../../out-tsc/lib", |
||||
|
"target": "es2015", |
||||
|
"declaration": true, |
||||
|
"declarationMap": true, |
||||
|
"inlineSources": true, |
||||
|
"types": [], |
||||
|
"lib": [ |
||||
|
"dom", |
||||
|
"es2018" |
||||
|
] |
||||
|
}, |
||||
|
"exclude": [ |
||||
|
"src/test.ts", |
||||
|
"**/*.spec.ts" |
||||
|
] |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
||||
|
{ |
||||
|
"extends": "./tsconfig.lib.json", |
||||
|
"compilerOptions": { |
||||
|
"declarationMap": false |
||||
|
}, |
||||
|
"angularCompilerOptions": { |
||||
|
"compilationMode": "partial" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
||||
|
{ |
||||
|
"extends": "../../tsconfig.json", |
||||
|
"compilerOptions": { |
||||
|
"outDir": "../../out-tsc/spec", |
||||
|
"types": [ |
||||
|
"jasmine" |
||||
|
] |
||||
|
}, |
||||
|
"files": [ |
||||
|
"src/test.ts" |
||||
|
], |
||||
|
"include": [ |
||||
|
"**/*.spec.ts", |
||||
|
"**/*.d.ts" |
||||
|
] |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../dist/<%= kebab(target) %>/<%= kebab(libraryName) %>", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
import { ModuleWithProviders, NgModule } from '@angular/core'; |
||||
|
|
||||
|
@NgModule() |
||||
|
export class <%= pascal(target) %><%= pascal(libraryName) %>Module { |
||||
|
static forRoot(): ModuleWithProviders<<%= pascal(target) %><%= pascal(libraryName) %>Module> { |
||||
|
return { |
||||
|
ngModule:<%= pascal(target) %><%= pascal(libraryName) %>Module, |
||||
|
providers: [] |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './<%= kebab(target) %>-<%= kebab(libraryName) %>.module'; |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './lib/index'; |
||||
@ -0,0 +1,159 @@ |
|||||
|
import { |
||||
|
applyTemplates, |
||||
|
chain, |
||||
|
move, |
||||
|
noop, |
||||
|
Rule, |
||||
|
SchematicContext, |
||||
|
SchematicsException, |
||||
|
Tree, |
||||
|
url, |
||||
|
} from '@angular-devkit/schematics'; |
||||
|
import { GenerateLibSchema } from './models/generate-lib-schema'; |
||||
|
import { |
||||
|
applyWithOverwrite, |
||||
|
getWorkspace, |
||||
|
interpolate, |
||||
|
isLibrary, |
||||
|
JSONFile, |
||||
|
kebab, |
||||
|
resolveProject, |
||||
|
updateWorkspace, |
||||
|
} from '../../utils'; |
||||
|
import * as cases from '../../utils/text'; |
||||
|
import { Exception } from '../../enums'; |
||||
|
import { join, normalize } from '@angular-devkit/core'; |
||||
|
import { |
||||
|
ProjectDefinition, |
||||
|
WorkspaceDefinition, |
||||
|
} from '@angular-devkit/core/src/workspace/definitions'; |
||||
|
import { addLibToWorkspaceFile } from '../../utils/angular-schematic/generate-lib'; |
||||
|
|
||||
|
export default function (schema: GenerateLibSchema) { |
||||
|
return async (tree: Tree) => { |
||||
|
if (schema.override || !(await checkLibExist(schema, tree))) { |
||||
|
return chain([createLibrary(schema)]); |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
async function checkLibExist(options: GenerateLibSchema, tree: Tree) { |
||||
|
const packageName = kebab(options.packageName); |
||||
|
if (options.isSecondaryEntrypoint) { |
||||
|
const lib = await resolveProject(tree, options.target); |
||||
|
const ngPackagePath = `${lib?.definition.root}/${packageName}/ng-package.json`; |
||||
|
const packageInfo = tree.read(ngPackagePath); |
||||
|
if (packageInfo) { |
||||
|
throw new SchematicsException( |
||||
|
interpolate(Exception.LibraryAlreadyExists, `${lib.name}/${packageName}`), |
||||
|
); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
const target = await resolveProject(tree, options.packageName, null); |
||||
|
if (target) { |
||||
|
throw new SchematicsException(interpolate(Exception.LibraryAlreadyExists, packageName)); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
function createLibrary(options: GenerateLibSchema): Rule { |
||||
|
return async (tree: Tree, _context: SchematicContext) => { |
||||
|
const target = await resolveProject(tree, options.packageName, null); |
||||
|
if (!target || options.override) { |
||||
|
if (options.isModuleTemplate) { |
||||
|
return createLibFromModuleTemplate(tree, options); |
||||
|
} |
||||
|
if (options.isSecondaryEntrypoint) { |
||||
|
return createLibSecondaryEntry(tree, options); |
||||
|
} |
||||
|
} else { |
||||
|
throw new SchematicsException( |
||||
|
interpolate(Exception.LibraryAlreadyExists, options.packageName), |
||||
|
); |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
async function resolvePackagesDirFromAngularJson(host: Tree) { |
||||
|
const workspace = await getWorkspace(host); |
||||
|
const projectFolder = readFirstLibInAngularJson(workspace); |
||||
|
return projectFolder?.root?.split('/')?.[0] || 'projects'; |
||||
|
} |
||||
|
|
||||
|
function readFirstLibInAngularJson(workspace: WorkspaceDefinition): ProjectDefinition | undefined { |
||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
const [_, props] = |
||||
|
Array.from(workspace.projects.entries()).find(([_, value]) => isLibrary(value)) || []; |
||||
|
return props; |
||||
|
} |
||||
|
|
||||
|
async function createLibFromModuleTemplate(tree: Tree, options: GenerateLibSchema) { |
||||
|
const packagesDir = await resolvePackagesDirFromAngularJson(tree); |
||||
|
const packageJson = JSON.parse(tree.read('./package.json')!.toString()); |
||||
|
const abpVersion = packageJson.dependencies['@abp/ng.core']; |
||||
|
|
||||
|
return chain([ |
||||
|
applyWithOverwrite(url('./files-package'), [ |
||||
|
applyTemplates({ |
||||
|
...cases, |
||||
|
libraryName: options.packageName, |
||||
|
abpVersion, |
||||
|
}), |
||||
|
move(normalize(packagesDir)), |
||||
|
]), |
||||
|
addLibToWorkspaceIfNotExist(options.packageName, packagesDir), |
||||
|
]); |
||||
|
} |
||||
|
|
||||
|
export function addLibToWorkspaceIfNotExist(name: string, packagesDir: string): Rule { |
||||
|
return async (tree: Tree, _: SchematicContext) => { |
||||
|
const workspace = await getWorkspace(tree); |
||||
|
const packageName = kebab(name); |
||||
|
const isProjectExist = workspace.projects.has(packageName); |
||||
|
|
||||
|
const projectRoot = join(normalize(packagesDir), packageName); |
||||
|
const pathImportLib = `${packagesDir}/${packageName}`; |
||||
|
|
||||
|
return chain([ |
||||
|
isProjectExist |
||||
|
? updateWorkspace(w => { |
||||
|
w.projects.delete(packageName); |
||||
|
}) |
||||
|
: noop(), |
||||
|
addLibToWorkspaceFile(projectRoot, packageName), |
||||
|
updateTsConfig(packageName, pathImportLib), |
||||
|
]); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export function updateTsConfig(packageName: string, path: string) { |
||||
|
return (host: Tree) => { |
||||
|
const files = ['tsconfig.json', 'tsconfig.app.json', 'tsconfig.base.json']; |
||||
|
const tsConfig = files.find(f => host.exists(f)); |
||||
|
if (!tsConfig) { |
||||
|
return host; |
||||
|
} |
||||
|
|
||||
|
const file = new JSONFile(host, tsConfig); |
||||
|
const jsonPath = ['compilerOptions', 'paths', packageName]; |
||||
|
file.modify(jsonPath, [`${path}/src/public-api.ts`]); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export async function createLibSecondaryEntry(tree: Tree, options: GenerateLibSchema) { |
||||
|
const targetLib = await resolveProject(tree, options.target); |
||||
|
const packageName = `${kebab(targetLib.name)}/${kebab(options.packageName)}`; |
||||
|
const importPath = `${targetLib.definition.root}/${kebab(options.packageName)}`; |
||||
|
return chain([ |
||||
|
applyWithOverwrite(url('./files-secondary-entrypoint'), [ |
||||
|
applyTemplates({ |
||||
|
...cases, |
||||
|
libraryName: options.packageName, |
||||
|
target: targetLib.name, |
||||
|
}), |
||||
|
move(normalize(targetLib.definition.root)), |
||||
|
updateTsConfig(packageName, importPath), |
||||
|
]), |
||||
|
]); |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
export interface GenerateLibSchema { |
||||
|
/** |
||||
|
* Angular package name will create |
||||
|
*/ |
||||
|
packageName: string; |
||||
|
|
||||
|
/** |
||||
|
* İs the package a library or a library module |
||||
|
*/ |
||||
|
isSecondaryEntrypoint: boolean; |
||||
|
|
||||
|
isModuleTemplate: boolean; |
||||
|
|
||||
|
override: boolean; |
||||
|
|
||||
|
target: string; |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './generate-lib-schema'; |
||||
@ -0,0 +1,36 @@ |
|||||
|
{ |
||||
|
"$schema": "http://json-schema.org/schema", |
||||
|
"$id": "SchematicsABPModuleTemplateCreator", |
||||
|
"title": "ABP Module Template Generator API Schema", |
||||
|
"type": "object", |
||||
|
"properties": { |
||||
|
"packageName": { |
||||
|
"description": "The name of the package will create", |
||||
|
"type": "string", |
||||
|
"$default": { |
||||
|
"$source": "argv", |
||||
|
"index": 0 |
||||
|
}, |
||||
|
"x-prompt": "Please enter the package name will create" |
||||
|
}, |
||||
|
"isSecondaryEntrypoint": { |
||||
|
"description": "Is secondary entrypoint", |
||||
|
"type": "boolean", |
||||
|
"$default": false, |
||||
|
"x-prompt": "Is secondary entrypoint?" |
||||
|
}, |
||||
|
"isModuleTemplate": { |
||||
|
"description": "Is module template", |
||||
|
"type": "boolean", |
||||
|
"$default": true, |
||||
|
"x-prompt": "Is module template?" |
||||
|
}, |
||||
|
"override": { |
||||
|
"description": "Override existing files", |
||||
|
"type": "boolean", |
||||
|
"$default": false, |
||||
|
"x-prompt": "Override existing files?" |
||||
|
} |
||||
|
}, |
||||
|
"required": [] |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export const NOT_FOUND_VALUE = Symbol('NOT_FOUND_VALUE'); |
||||
@ -0,0 +1,52 @@ |
|||||
|
import { Rule, Tree } from '@angular-devkit/schematics'; |
||||
|
import { Builders, JSONFile, ProjectType, updateWorkspace } from '../angular'; |
||||
|
|
||||
|
export function updateTsConfig(packageName: string, ...paths: string[]) { |
||||
|
return (host: Tree) => { |
||||
|
if (!host.exists('tsconfig.json')) { |
||||
|
return host; |
||||
|
} |
||||
|
|
||||
|
const file = new JSONFile(host, 'tsconfig.json'); |
||||
|
const jsonPath = ['compilerOptions', 'paths', packageName]; |
||||
|
const value = file.get(jsonPath); |
||||
|
file.modify(jsonPath, Array.isArray(value) ? [...value, ...paths] : paths); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export function addLibToWorkspaceFile(projectRoot: string, projectName: string): Rule { |
||||
|
return updateWorkspace(workspace => { |
||||
|
workspace.projects.add({ |
||||
|
name: projectName, |
||||
|
root: projectRoot, |
||||
|
sourceRoot: `${projectRoot}/src`, |
||||
|
projectType: ProjectType.Library, |
||||
|
prefix: 'lib', |
||||
|
targets: { |
||||
|
build: { |
||||
|
builder: Builders.NgPackagr, |
||||
|
defaultConfiguration: 'production', |
||||
|
options: { |
||||
|
project: `${projectRoot}/ng-package.json`, |
||||
|
}, |
||||
|
configurations: { |
||||
|
production: { |
||||
|
tsConfig: `${projectRoot}/tsconfig.lib.prod.json`, |
||||
|
}, |
||||
|
development: { |
||||
|
tsConfig: `${projectRoot}/tsconfig.lib.json`, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
test: { |
||||
|
builder: Builders.Karma, |
||||
|
options: { |
||||
|
main: `${projectRoot}/src/test.ts`, |
||||
|
tsConfig: `${projectRoot}/tsconfig.spec.json`, |
||||
|
karmaConfig: `${projectRoot}/karma.conf.js`, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './generate-lib'; |
||||
@ -1,5 +1,5 @@ |
|||||
**DISCLAIMER** |
**DISCLAIMER** |
||||
|
|
||||
This directory is a direct copy of https://github.com/angular/angular-cli/tree/master/packages/schematics/angular/utility and is used under terms and permissions by the MIT license granted by Google, Inc. |
This directory is a direct copy of https://github.com/angular/angular-cli/tree/d091bb0c7b76a73e1b7d4b5690c532c68452b1d6 and is used under terms and permissions by the MIT license granted by Google, Inc. |
||||
|
|
||||
All credits go to Angular team for building these utilities. |
All credits go to Angular team for building these utilities. |
||||
|
|||||
@ -1,541 +0,0 @@ |
|||||
/* eslint-disable @typescript-eslint/ban-types */ |
|
||||
/** |
|
||||
* @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
|
|
||||
*/ |
|
||||
import { JsonParseMode, parseJson } from '@angular-devkit/core'; |
|
||||
import { Rule, SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics'; |
|
||||
import { ProjectType, WorkspaceProject, WorkspaceSchema } from './workspace-models'; |
|
||||
|
|
||||
// The interfaces below are generated from the Angular CLI configuration schema
|
|
||||
// https://github.com/angular/angular-cli/blob/master/packages/@angular/cli/lib/config/schema.json
|
|
||||
export interface AppConfig { |
|
||||
/** |
|
||||
* Name of the app. |
|
||||
*/ |
|
||||
name?: string; |
|
||||
/** |
|
||||
* Directory where app files are placed. |
|
||||
*/ |
|
||||
appRoot?: string; |
|
||||
/** |
|
||||
* The root directory of the app. |
|
||||
*/ |
|
||||
root?: string; |
|
||||
/** |
|
||||
* The output directory for build results. |
|
||||
*/ |
|
||||
outDir?: string; |
|
||||
/** |
|
||||
* List of application assets. |
|
||||
*/ |
|
||||
assets?: ( |
|
||||
| string |
|
||||
| { |
|
||||
/** |
|
||||
* The pattern to match. |
|
||||
*/ |
|
||||
glob?: string; |
|
||||
/** |
|
||||
* The dir to search within. |
|
||||
*/ |
|
||||
input?: string; |
|
||||
/** |
|
||||
* The output path (relative to the outDir). |
|
||||
*/ |
|
||||
output?: string; |
|
||||
} |
|
||||
)[]; |
|
||||
/** |
|
||||
* URL where files will be deployed. |
|
||||
*/ |
|
||||
deployUrl?: string; |
|
||||
/** |
|
||||
* Base url for the application being built. |
|
||||
*/ |
|
||||
baseHref?: string; |
|
||||
/** |
|
||||
* The runtime platform of the app. |
|
||||
*/ |
|
||||
platform?: 'browser' | 'server'; |
|
||||
/** |
|
||||
* The name of the start HTML file. |
|
||||
*/ |
|
||||
index?: string; |
|
||||
/** |
|
||||
* The name of the main entry-point file. |
|
||||
*/ |
|
||||
main?: string; |
|
||||
/** |
|
||||
* The name of the polyfills file. |
|
||||
*/ |
|
||||
polyfills?: string; |
|
||||
/** |
|
||||
* The name of the test entry-point file. |
|
||||
*/ |
|
||||
test?: string; |
|
||||
/** |
|
||||
* The name of the TypeScript configuration file. |
|
||||
*/ |
|
||||
tsconfig?: string; |
|
||||
/** |
|
||||
* The name of the TypeScript configuration file for unit tests. |
|
||||
*/ |
|
||||
testTsconfig?: string; |
|
||||
/** |
|
||||
* The prefix to apply to generated selectors. |
|
||||
*/ |
|
||||
prefix?: string; |
|
||||
/** |
|
||||
* Experimental support for a service worker from @angular/service-worker. |
|
||||
*/ |
|
||||
serviceWorker?: boolean; |
|
||||
/** |
|
||||
* Global styles to be included in the build. |
|
||||
*/ |
|
||||
styles?: ( |
|
||||
| string |
|
||||
| { |
|
||||
input?: string; |
|
||||
[name: string]: any; |
|
||||
} |
|
||||
)[]; |
|
||||
/** |
|
||||
* Options to pass to style preprocessors |
|
||||
*/ |
|
||||
stylePreprocessorOptions?: { |
|
||||
/** |
|
||||
* Paths to include. Paths will be resolved to project root. |
|
||||
*/ |
|
||||
includePaths?: string[]; |
|
||||
}; |
|
||||
/** |
|
||||
* Global scripts to be included in the build. |
|
||||
*/ |
|
||||
scripts?: ( |
|
||||
| string |
|
||||
| { |
|
||||
input: string; |
|
||||
[name: string]: any; |
|
||||
} |
|
||||
)[]; |
|
||||
/** |
|
||||
* Source file for environment config. |
|
||||
*/ |
|
||||
environmentSource?: string; |
|
||||
/** |
|
||||
* Name and corresponding file for environment config. |
|
||||
*/ |
|
||||
environments?: { |
|
||||
[name: string]: any; |
|
||||
}; |
|
||||
appShell?: { |
|
||||
app: string; |
|
||||
route: string; |
|
||||
}; |
|
||||
budgets?: { |
|
||||
/** |
|
||||
* The type of budget |
|
||||
*/ |
|
||||
type?: 'bundle' | 'initial' | 'allScript' | 'all' | 'anyScript' | 'any' | 'anyComponentStyle'; |
|
||||
/** |
|
||||
* The name of the bundle |
|
||||
*/ |
|
||||
name?: string; |
|
||||
/** |
|
||||
* The baseline size for comparison. |
|
||||
*/ |
|
||||
baseline?: string; |
|
||||
/** |
|
||||
* The maximum threshold for warning relative to the baseline. |
|
||||
*/ |
|
||||
maximumWarning?: string; |
|
||||
/** |
|
||||
* The maximum threshold for error relative to the baseline. |
|
||||
*/ |
|
||||
maximumError?: string; |
|
||||
/** |
|
||||
* The minimum threshold for warning relative to the baseline. |
|
||||
*/ |
|
||||
minimumWarning?: string; |
|
||||
/** |
|
||||
* The minimum threshold for error relative to the baseline. |
|
||||
*/ |
|
||||
minimumError?: string; |
|
||||
/** |
|
||||
* The threshold for warning relative to the baseline (min & max). |
|
||||
*/ |
|
||||
warning?: string; |
|
||||
/** |
|
||||
* The threshold for error relative to the baseline (min & max). |
|
||||
*/ |
|
||||
error?: string; |
|
||||
}[]; |
|
||||
} |
|
||||
|
|
||||
export interface CliConfig { |
|
||||
$schema?: string; |
|
||||
/** |
|
||||
* The global configuration of the project. |
|
||||
*/ |
|
||||
project?: { |
|
||||
/** |
|
||||
* The name of the project. |
|
||||
*/ |
|
||||
name?: string; |
|
||||
/** |
|
||||
* Whether or not this project was ejected. |
|
||||
*/ |
|
||||
ejected?: boolean; |
|
||||
}; |
|
||||
/** |
|
||||
* Properties of the different applications in this project. |
|
||||
*/ |
|
||||
apps?: AppConfig[]; |
|
||||
/** |
|
||||
* Configuration for end-to-end tests. |
|
||||
*/ |
|
||||
e2e?: { |
|
||||
protractor?: { |
|
||||
/** |
|
||||
* Path to the config file. |
|
||||
*/ |
|
||||
config?: string; |
|
||||
}; |
|
||||
}; |
|
||||
/** |
|
||||
* Properties to be passed to TSLint. |
|
||||
*/ |
|
||||
lint?: { |
|
||||
/** |
|
||||
* File glob(s) to lint. |
|
||||
*/ |
|
||||
files?: string | string[]; |
|
||||
/** |
|
||||
* Location of the tsconfig.json project file. |
|
||||
* Will also use as files to lint if 'files' property not present. |
|
||||
*/ |
|
||||
project: string; |
|
||||
/** |
|
||||
* Location of the tslint.json configuration. |
|
||||
*/ |
|
||||
tslintConfig?: string; |
|
||||
/** |
|
||||
* File glob(s) to ignore. |
|
||||
*/ |
|
||||
exclude?: string | string[]; |
|
||||
}[]; |
|
||||
/** |
|
||||
* Configuration for unit tests. |
|
||||
*/ |
|
||||
test?: { |
|
||||
karma?: { |
|
||||
/** |
|
||||
* Path to the karma config file. |
|
||||
*/ |
|
||||
config?: string; |
|
||||
}; |
|
||||
codeCoverage?: { |
|
||||
/** |
|
||||
* Globs to exclude from code coverage. |
|
||||
*/ |
|
||||
exclude?: string[]; |
|
||||
}; |
|
||||
}; |
|
||||
/** |
|
||||
* Specify the default values for generating. |
|
||||
*/ |
|
||||
defaults?: { |
|
||||
/** |
|
||||
* The file extension to be used for style files. |
|
||||
*/ |
|
||||
styleExt?: string; |
|
||||
/** |
|
||||
* How often to check for file updates. |
|
||||
*/ |
|
||||
poll?: number; |
|
||||
/** |
|
||||
* Use lint to fix files after generation |
|
||||
*/ |
|
||||
lintFix?: boolean; |
|
||||
/** |
|
||||
* Options for generating a class. |
|
||||
*/ |
|
||||
class?: { |
|
||||
/** |
|
||||
* Specifies if a spec file is generated. |
|
||||
*/ |
|
||||
spec?: boolean; |
|
||||
}; |
|
||||
/** |
|
||||
* Options for generating a component. |
|
||||
*/ |
|
||||
component?: { |
|
||||
/** |
|
||||
* Flag to indicate if a directory is created. |
|
||||
*/ |
|
||||
flat?: boolean; |
|
||||
/** |
|
||||
* Specifies if a spec file is generated. |
|
||||
*/ |
|
||||
spec?: boolean; |
|
||||
/** |
|
||||
* 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'; |
|
||||
}; |
|
||||
/** |
|
||||
* Options for generating a directive. |
|
||||
*/ |
|
||||
directive?: { |
|
||||
/** |
|
||||
* Flag to indicate if a directory is created. |
|
||||
*/ |
|
||||
flat?: boolean; |
|
||||
/** |
|
||||
* Specifies if a spec file is generated. |
|
||||
*/ |
|
||||
spec?: boolean; |
|
||||
}; |
|
||||
/** |
|
||||
* Options for generating a guard. |
|
||||
*/ |
|
||||
guard?: { |
|
||||
/** |
|
||||
* Flag to indicate if a directory is created. |
|
||||
*/ |
|
||||
flat?: boolean; |
|
||||
/** |
|
||||
* Specifies if a spec file is generated. |
|
||||
*/ |
|
||||
spec?: boolean; |
|
||||
}; |
|
||||
/** |
|
||||
* Options for generating an interface. |
|
||||
*/ |
|
||||
interface?: { |
|
||||
/** |
|
||||
* Prefix to apply to interface names. (i.e. I) |
|
||||
*/ |
|
||||
prefix?: string; |
|
||||
}; |
|
||||
/** |
|
||||
* Options for generating a module. |
|
||||
*/ |
|
||||
module?: { |
|
||||
/** |
|
||||
* Flag to indicate if a directory is created. |
|
||||
*/ |
|
||||
flat?: boolean; |
|
||||
/** |
|
||||
* Specifies if a spec file is generated. |
|
||||
*/ |
|
||||
spec?: boolean; |
|
||||
}; |
|
||||
/** |
|
||||
* Options for generating a pipe. |
|
||||
*/ |
|
||||
pipe?: { |
|
||||
/** |
|
||||
* Flag to indicate if a directory is created. |
|
||||
*/ |
|
||||
flat?: boolean; |
|
||||
/** |
|
||||
* Specifies if a spec file is generated. |
|
||||
*/ |
|
||||
spec?: boolean; |
|
||||
}; |
|
||||
/** |
|
||||
* Options for generating a service. |
|
||||
*/ |
|
||||
service?: { |
|
||||
/** |
|
||||
* Flag to indicate if a directory is created. |
|
||||
*/ |
|
||||
flat?: boolean; |
|
||||
/** |
|
||||
* Specifies if a spec file is generated. |
|
||||
*/ |
|
||||
spec?: boolean; |
|
||||
}; |
|
||||
/** |
|
||||
* Properties to be passed to the build command. |
|
||||
*/ |
|
||||
build?: { |
|
||||
/** |
|
||||
* Output sourcemaps. |
|
||||
*/ |
|
||||
sourcemaps?: boolean; |
|
||||
/** |
|
||||
* Base url for the application being built. |
|
||||
*/ |
|
||||
baseHref?: string; |
|
||||
/** |
|
||||
* The ssl key used by the server. |
|
||||
*/ |
|
||||
progress?: boolean; |
|
||||
/** |
|
||||
* Enable and define the file watching poll time period (milliseconds). |
|
||||
*/ |
|
||||
poll?: number; |
|
||||
/** |
|
||||
* Delete output path before build. |
|
||||
*/ |
|
||||
deleteOutputPath?: boolean; |
|
||||
/** |
|
||||
* Do not use the real path when resolving modules. |
|
||||
*/ |
|
||||
preserveSymlinks?: boolean; |
|
||||
/** |
|
||||
* Show circular dependency warnings on builds. |
|
||||
*/ |
|
||||
showCircularDependencies?: boolean; |
|
||||
/** |
|
||||
* Use a separate bundle containing code used across multiple bundles. |
|
||||
*/ |
|
||||
commonChunk?: boolean; |
|
||||
/** |
|
||||
* Use file name for lazy loaded chunks. |
|
||||
*/ |
|
||||
namedChunks?: boolean; |
|
||||
}; |
|
||||
/** |
|
||||
* Properties to be passed to the serve command. |
|
||||
*/ |
|
||||
serve?: { |
|
||||
/** |
|
||||
* The port the application will be served on. |
|
||||
*/ |
|
||||
port?: number; |
|
||||
/** |
|
||||
* The host the application will be served on. |
|
||||
*/ |
|
||||
host?: string; |
|
||||
/** |
|
||||
* Enables ssl for the application. |
|
||||
*/ |
|
||||
ssl?: boolean; |
|
||||
/** |
|
||||
* The ssl key used by the server. |
|
||||
*/ |
|
||||
sslKey?: string; |
|
||||
/** |
|
||||
* The ssl certificate used by the server. |
|
||||
*/ |
|
||||
sslCert?: string; |
|
||||
/** |
|
||||
* Proxy configuration file. |
|
||||
*/ |
|
||||
proxyConfig?: string; |
|
||||
}; |
|
||||
/** |
|
||||
* Properties about schematics. |
|
||||
*/ |
|
||||
schematics?: { |
|
||||
/** |
|
||||
* The schematics collection to use. |
|
||||
*/ |
|
||||
collection?: string; |
|
||||
/** |
|
||||
* The new app schematic. |
|
||||
*/ |
|
||||
newApp?: string; |
|
||||
}; |
|
||||
}; |
|
||||
/** |
|
||||
* Specify which package manager tool to use. |
|
||||
*/ |
|
||||
packageManager?: 'npm' | 'cnpm' | 'yarn' | 'default'; |
|
||||
/** |
|
||||
* Allow people to disable console warnings. |
|
||||
*/ |
|
||||
warnings?: { |
|
||||
versionMismatch?: boolean; |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
export function getWorkspacePath(host: Tree): string { |
|
||||
const possibleFiles = ['/angular.json', '/.angular.json']; |
|
||||
const path = possibleFiles.filter(path => host.exists(path))[0]; |
|
||||
|
|
||||
return path; |
|
||||
} |
|
||||
|
|
||||
export function getWorkspaceSchema(host: Tree): WorkspaceSchema { |
|
||||
const path = getWorkspacePath(host); |
|
||||
const configBuffer = host.read(path); |
|
||||
if (configBuffer === null) { |
|
||||
throw new SchematicsException(`Could not find (${path})`); |
|
||||
} |
|
||||
const content = configBuffer.toString(); |
|
||||
|
|
||||
return parseJson(content, JsonParseMode.Loose) as {} as WorkspaceSchema; |
|
||||
} |
|
||||
|
|
||||
export function addProjectToWorkspace<TProjectType extends ProjectType = ProjectType.Application>( |
|
||||
workspace: WorkspaceSchema, |
|
||||
name: string, |
|
||||
project: WorkspaceProject<TProjectType>, |
|
||||
): Rule { |
|
||||
return (_host: Tree, _context: SchematicContext) => { |
|
||||
if (workspace.projects[name]) { |
|
||||
throw new Error(`Project '${name}' already exists in workspace.`); |
|
||||
} |
|
||||
|
|
||||
// Add project to workspace.
|
|
||||
workspace.projects[name] = project; |
|
||||
|
|
||||
if (!workspace.defaultProject && Object.keys(workspace.projects).length === 1) { |
|
||||
// Make the new project the default one.
|
|
||||
workspace.defaultProject = name; |
|
||||
} |
|
||||
|
|
||||
return updateWorkspaceSchema(workspace); |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
export function updateWorkspaceSchema(workspace: WorkspaceSchema): Rule { |
|
||||
return (host: Tree, _context: SchematicContext) => { |
|
||||
host.overwrite(getWorkspacePath(host), JSON.stringify(workspace, null, 2)); |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
export const configPath = '/.angular-cli.json'; |
|
||||
|
|
||||
export function getConfig(host: Tree): CliConfig { |
|
||||
const configBuffer = host.read(configPath); |
|
||||
if (configBuffer === null) { |
|
||||
throw new SchematicsException('Could not find .angular-cli.json'); |
|
||||
} |
|
||||
|
|
||||
const config = parseJson(configBuffer.toString(), JsonParseMode.Loose) as {} as CliConfig; |
|
||||
|
|
||||
return config; |
|
||||
} |
|
||||
|
|
||||
export function getAppFromConfig(config: CliConfig, appIndexOrName: string): AppConfig | null { |
|
||||
if (!config.apps) { |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
if (parseInt(appIndexOrName) >= 0) { |
|
||||
return config.apps[parseInt(appIndexOrName)]; |
|
||||
} |
|
||||
|
|
||||
return config.apps.filter(app => app.name === appIndexOrName)[0]; |
|
||||
} |
|
||||
@ -0,0 +1,61 @@ |
|||||
|
/** |
||||
|
* @license |
||||
|
* Copyright Google LLC 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
|
||||
|
*/ |
||||
|
|
||||
|
import { strings } from '@angular-devkit/core'; |
||||
|
import { |
||||
|
apply, |
||||
|
applyTemplates, |
||||
|
chain, |
||||
|
filter, |
||||
|
mergeWith, |
||||
|
move, |
||||
|
noop, |
||||
|
Rule, |
||||
|
Tree, |
||||
|
url, |
||||
|
} from '@angular-devkit/schematics'; |
||||
|
import { parseName } from './parse-name'; |
||||
|
import { createDefaultPath } from './workspace'; |
||||
|
|
||||
|
export interface GenerateFromFilesOptions { |
||||
|
flat?: boolean; |
||||
|
name: string; |
||||
|
path?: string; |
||||
|
prefix?: string; |
||||
|
project?: string; |
||||
|
skipTests?: boolean; |
||||
|
} |
||||
|
|
||||
|
export function generateFromFiles( |
||||
|
options: GenerateFromFilesOptions, |
||||
|
extraTemplateValues: Record<string, string | ((v: string) => string)> = {}, |
||||
|
): Rule { |
||||
|
return async (host: Tree) => { |
||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
|
// @ts-ignore
|
||||
|
options.path ??= await createDefaultPath(host, options.project as string); |
||||
|
options.prefix ??= ''; |
||||
|
options.flat ??= true; |
||||
|
|
||||
|
const parsedPath = parseName(options.path!, options.name); |
||||
|
options.name = parsedPath.name; |
||||
|
options.path = parsedPath.path; |
||||
|
|
||||
|
const templateSource = apply(url('./files'), [ |
||||
|
options.skipTests ? filter(path => !path.endsWith('.spec.ts.template')) : noop(), |
||||
|
applyTemplates({ |
||||
|
...strings, |
||||
|
...options, |
||||
|
...extraTemplateValues, |
||||
|
}), |
||||
|
move(parsedPath.path + (options.flat ? '' : '/' + strings.dasherize(options.name))), |
||||
|
]); |
||||
|
|
||||
|
return chain([mergeWith(templateSource)]); |
||||
|
}; |
||||
|
} |
||||
@ -1,17 +1,13 @@ |
|||||
export * from './ast-utils'; |
export * from './ast-utils'; |
||||
export * from './change'; |
export * from './change'; |
||||
export * from './config'; |
|
||||
export * from './dependencies'; |
export * from './dependencies'; |
||||
export * from './find-module'; |
export * from './find-module'; |
||||
|
export * from './generate-from-files'; |
||||
export * from './json-file'; |
export * from './json-file'; |
||||
export * from './json-utils'; |
|
||||
export * from './latest-versions'; |
|
||||
export * from './lint-fix'; |
|
||||
export * from './ng-ast-utils'; |
export * from './ng-ast-utils'; |
||||
export * from './parse-name'; |
export * from './parse-name'; |
||||
export * from './paths'; |
export * from './paths'; |
||||
export * from './project-targets'; |
export * from './project-targets'; |
||||
export * from './tsconfig'; |
|
||||
export * from './validation'; |
export * from './validation'; |
||||
export * from './workspace'; |
export * from './workspace'; |
||||
export * from './workspace-models'; |
export * from './workspace-models'; |
||||
|
|||||
@ -1,221 +0,0 @@ |
|||||
/** |
|
||||
* @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
|
|
||||
*/ |
|
||||
import { |
|
||||
JsonAstArray, |
|
||||
JsonAstKeyValue, |
|
||||
JsonAstNode, |
|
||||
JsonAstObject, |
|
||||
JsonValue, |
|
||||
} from '@angular-devkit/core'; |
|
||||
import { UpdateRecorder } from '@angular-devkit/schematics'; |
|
||||
|
|
||||
export function appendPropertyInAstObject( |
|
||||
recorder: UpdateRecorder, |
|
||||
node: JsonAstObject, |
|
||||
propertyName: string, |
|
||||
value: JsonValue, |
|
||||
indent: number, |
|
||||
) { |
|
||||
const indentStr = _buildIndent(indent); |
|
||||
let index = node.start.offset + 1; |
|
||||
if (node.properties.length > 0) { |
|
||||
// Insert comma.
|
|
||||
const last = node.properties[node.properties.length - 1]; |
|
||||
const { text, end } = last; |
|
||||
const commaIndex = text.endsWith('\n') ? end.offset - 1 : end.offset; |
|
||||
recorder.insertRight(commaIndex, ','); |
|
||||
index = end.offset; |
|
||||
} |
|
||||
const content = _stringifyContent(value, indentStr); |
|
||||
recorder.insertRight( |
|
||||
index, |
|
||||
(node.properties.length === 0 && indent ? '\n' : '') + |
|
||||
' '.repeat(indent) + |
|
||||
`"${propertyName}":${indent ? ' ' : ''}${content}` + |
|
||||
indentStr.slice(0, -indent), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
export function insertPropertyInAstObjectInOrder( |
|
||||
recorder: UpdateRecorder, |
|
||||
node: JsonAstObject, |
|
||||
propertyName: string, |
|
||||
value: JsonValue, |
|
||||
indent: number, |
|
||||
) { |
|
||||
if (node.properties.length === 0) { |
|
||||
appendPropertyInAstObject(recorder, node, propertyName, value, indent); |
|
||||
|
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
// Find insertion info.
|
|
||||
let insertAfterProp: JsonAstKeyValue | null = null; |
|
||||
let prev: JsonAstKeyValue | null = null; |
|
||||
let isLastProp = false; |
|
||||
const last = node.properties[node.properties.length - 1]; |
|
||||
for (const prop of node.properties) { |
|
||||
if (prop.key.value > propertyName) { |
|
||||
if (prev) { |
|
||||
insertAfterProp = prev; |
|
||||
} |
|
||||
break; |
|
||||
} |
|
||||
if (prop === last) { |
|
||||
isLastProp = true; |
|
||||
insertAfterProp = last; |
|
||||
} |
|
||||
prev = prop; |
|
||||
} |
|
||||
|
|
||||
if (isLastProp) { |
|
||||
appendPropertyInAstObject(recorder, node, propertyName, value, indent); |
|
||||
|
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
const indentStr = _buildIndent(indent); |
|
||||
const insertIndex = |
|
||||
insertAfterProp === null ? node.start.offset + 1 : insertAfterProp.end.offset + 1; |
|
||||
const content = _stringifyContent(value, indentStr); |
|
||||
recorder.insertRight( |
|
||||
insertIndex, |
|
||||
indentStr + `"${propertyName}":${indent ? ' ' : ''}${content}` + ',', |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
export function removePropertyInAstObject( |
|
||||
recorder: UpdateRecorder, |
|
||||
node: JsonAstObject, |
|
||||
propertyName: string, |
|
||||
) { |
|
||||
// Find the property inside the object.
|
|
||||
const propIdx = node.properties.findIndex(prop => prop.key.value === propertyName); |
|
||||
|
|
||||
if (propIdx === -1) { |
|
||||
// There's nothing to remove.
|
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (node.properties.length === 1) { |
|
||||
// This is a special case. Everything should be removed, including indentation.
|
|
||||
recorder.remove(node.start.offset, node.end.offset - node.start.offset); |
|
||||
recorder.insertRight(node.start.offset, '{}'); |
|
||||
|
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
// The AST considers commas and indentation to be part of the preceding property.
|
|
||||
// To get around messy comma and identation management, we can work over the range between
|
|
||||
// two properties instead.
|
|
||||
const previousProp = node.properties[propIdx - 1]; |
|
||||
const targetProp = node.properties[propIdx]; |
|
||||
const nextProp = node.properties[propIdx + 1]; |
|
||||
|
|
||||
let start, end; |
|
||||
if (previousProp) { |
|
||||
// Given the object below, and intending to remove the `m` property:
|
|
||||
// "{\n \"a\": \"a\",\n \"m\": \"m\",\n \"z\": \"z\"\n}"
|
|
||||
// ^---------------^
|
|
||||
// Removing the range above results in:
|
|
||||
// "{\n \"a\": \"a\",\n \"z\": \"z\"\n}"
|
|
||||
start = previousProp.end; |
|
||||
end = targetProp.end; |
|
||||
} else { |
|
||||
// If there's no previousProp there is a nextProp, since we've specialcased the 1 length case.
|
|
||||
// Given the object below, and intending to remove the `a` property:
|
|
||||
// "{\n \"a\": \"a\",\n \"m\": \"m\",\n \"z\": \"z\"\n}"
|
|
||||
// ^---------------^
|
|
||||
// Removing the range above results in:
|
|
||||
// "{\n \"m\": \"m\",\n \"z\": \"z\"\n}"
|
|
||||
start = targetProp.start; |
|
||||
end = nextProp.start; |
|
||||
} |
|
||||
|
|
||||
recorder.remove(start.offset, end.offset - start.offset); |
|
||||
if (!nextProp) { |
|
||||
recorder.insertRight(start.offset, '\n'); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
export function appendValueInAstArray( |
|
||||
recorder: UpdateRecorder, |
|
||||
node: JsonAstArray, |
|
||||
value: JsonValue, |
|
||||
indent = 4, |
|
||||
) { |
|
||||
let indentStr = _buildIndent(indent); |
|
||||
let index = node.start.offset + 1; |
|
||||
let newNodes: any[] | undefined; |
|
||||
|
|
||||
if (node.elements.length > 0) { |
|
||||
// Insert comma.
|
|
||||
const { end } = node.elements[node.elements.length - 1]; |
|
||||
const isClosingOnSameLine = node.end.offset - end.offset === 1; |
|
||||
|
|
||||
if (isClosingOnSameLine && indent) { |
|
||||
// Reformat the entire array
|
|
||||
recorder.remove(node.start.offset, node.end.offset - node.start.offset); |
|
||||
newNodes = [...node.elements.map(({ value }) => value), value]; |
|
||||
index = node.start.offset; |
|
||||
// In case we are generating the entire node we need to reduce the spacing as
|
|
||||
// otherwise we'd end up having incorrect double spacing
|
|
||||
indent = indent - 2; |
|
||||
indentStr = _buildIndent(indent); |
|
||||
} else { |
|
||||
recorder.insertRight(end.offset, ','); |
|
||||
index = end.offset; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
recorder.insertRight( |
|
||||
index, |
|
||||
(newNodes ? '' : indentStr) + |
|
||||
_stringifyContent(newNodes || value, indentStr) + |
|
||||
(node.elements.length === 0 && indent ? indentStr.substr(0, -indent) + '\n' : ''), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
export function findPropertyInAstObject( |
|
||||
node: JsonAstObject, |
|
||||
propertyName: string, |
|
||||
): JsonAstNode | null { |
|
||||
let maybeNode: JsonAstNode | null = null; |
|
||||
for (const property of node.properties) { |
|
||||
if (property.key.value == propertyName) { |
|
||||
maybeNode = property.value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return maybeNode; |
|
||||
} |
|
||||
|
|
||||
function _buildIndent(count: number): string { |
|
||||
return count ? '\n' + ' '.repeat(count) : ''; |
|
||||
} |
|
||||
|
|
||||
function _stringifyContent(value: JsonValue, indentStr: string): string { |
|
||||
// TODO: Add snapshot tests
|
|
||||
|
|
||||
// The 'space' value is 2, because we want to add 2 additional
|
|
||||
// indents from the 'key' node.
|
|
||||
|
|
||||
// If we use the indent provided we will have double indents:
|
|
||||
// "budgets": [
|
|
||||
// {
|
|
||||
// "type": "initial",
|
|
||||
// "maximumWarning": "2mb",
|
|
||||
// "maximumError": "5mb"
|
|
||||
// },
|
|
||||
// {
|
|
||||
// "type": "anyComponentStyle",
|
|
||||
// 'maximumWarning": "5kb"
|
|
||||
// }
|
|
||||
// ]
|
|
||||
return JSON.stringify(value, null, 2).replace(/\n/g, indentStr); |
|
||||
} |
|
||||
@ -1,26 +0,0 @@ |
|||||
/** |
|
||||
* @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 const latestVersions = { |
|
||||
// These versions should be kept up to date with latest Angular peer dependencies.
|
|
||||
Angular: '~10.0.0-rc.0', |
|
||||
RxJs: '~6.6.0', |
|
||||
ZoneJs: '~0.10.2', |
|
||||
TypeScript: '~3.9.5', |
|
||||
TsLib: '^2.0.0', |
|
||||
|
|
||||
// The versions below must be manually updated when making a new devkit release.
|
|
||||
// For our e2e tests, these versions must match the latest tag present on the branch.
|
|
||||
// During RC periods they will not match the latest RC until there's a new git tag, and
|
|
||||
// should not be updated.
|
|
||||
DevkitBuildAngular: '~0.1000.0-rc.0', |
|
||||
DevkitBuildNgPackagr: '~0.1000.0-rc.0', |
|
||||
DevkitBuildWebpack: '~0.1000.0-rc.0', |
|
||||
|
|
||||
ngPackagr: '^10.0.0', |
|
||||
}; |
|
||||
@ -0,0 +1,20 @@ |
|||||
|
{ |
||||
|
"description": "Package versions used by schematics in @schematics/angular.", |
||||
|
"comment": "This file is needed so that depedencies are synced by Renovate.", |
||||
|
"private": true, |
||||
|
"dependencies": { |
||||
|
"@types/jasmine": "~3.10.0", |
||||
|
"@types/node": "^12.11.1", |
||||
|
"jasmine-core": "~4.0.0", |
||||
|
"karma-chrome-launcher": "~3.1.0", |
||||
|
"karma-coverage": "~2.1.0", |
||||
|
"karma-jasmine-html-reporter": "~1.7.0", |
||||
|
"karma-jasmine": "~4.0.0", |
||||
|
"karma": "~6.3.0", |
||||
|
"ng-packagr": "^13.0.0", |
||||
|
"rxjs": "~6.6.7", |
||||
|
"tslib": "^2.3.0", |
||||
|
"typescript": "~4.6.2", |
||||
|
"zone.js": "~0.11.4" |
||||
|
} |
||||
|
} |
||||
@ -1,54 +0,0 @@ |
|||||
/** |
|
||||
* @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
|
|
||||
*/ |
|
||||
import { |
|
||||
DirEntry, |
|
||||
Rule, |
|
||||
SchematicContext, |
|
||||
SchematicsException, |
|
||||
Tree, |
|
||||
} from '@angular-devkit/schematics'; |
|
||||
import { TslintFixTask } from '@angular-devkit/schematics/tasks'; |
|
||||
|
|
||||
export function applyLintFix(path = '/'): Rule { |
|
||||
return (tree: Tree, context: SchematicContext) => { |
|
||||
// Find the closest tslint.json or tslint.yaml
|
|
||||
let dir: DirEntry | null = tree.getDir(path.substr(0, path.lastIndexOf('/'))); |
|
||||
|
|
||||
do { |
|
||||
if ((dir.subfiles as string[]).some(f => f === 'tslint.json' || f === 'tslint.yaml')) { |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
dir = dir.parent; |
|
||||
} while (dir !== null); |
|
||||
|
|
||||
if (dir === null) { |
|
||||
throw new SchematicsException( |
|
||||
'Asked to run lint fixes, but could not find a tslint.json or tslint.yaml config file.', |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
// Only include files that have been touched.
|
|
||||
const files = tree.actions.reduce((acc: Set<string>, action) => { |
|
||||
const path = action.path.substr(1); // Remove the starting '/'.
|
|
||||
if (path.endsWith('.ts') && dir && action.path.startsWith(dir.path)) { |
|
||||
acc.add(path); |
|
||||
} |
|
||||
|
|
||||
return acc; |
|
||||
}, new Set<string>()); |
|
||||
|
|
||||
context.addTask( |
|
||||
new TslintFixTask({ |
|
||||
ignoreErrors: true, |
|
||||
tsConfigPath: 'tsconfig.json', |
|
||||
files: [...files], |
|
||||
}), |
|
||||
); |
|
||||
}; |
|
||||
} |
|
||||
@ -1,76 +0,0 @@ |
|||||
/** |
|
||||
* @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
|
|
||||
*/ |
|
||||
|
|
||||
import { JsonParseMode, parseJsonAst } from '@angular-devkit/core'; |
|
||||
import { Rule, SchematicsException, Tree } from '@angular-devkit/schematics'; |
|
||||
import { appendValueInAstArray, findPropertyInAstObject } from './json-utils'; |
|
||||
|
|
||||
const SOLUTION_TSCONFIG_PATH = 'tsconfig.json'; |
|
||||
|
|
||||
/** |
|
||||
* Add project references in "Solution Style" tsconfig. |
|
||||
*/ |
|
||||
export function addTsConfigProjectReferences(paths: string[]): Rule { |
|
||||
return (host, context) => { |
|
||||
const logger = context.logger; |
|
||||
|
|
||||
// We need to read after each write to avoid missing `,` when appending multiple items.
|
|
||||
for (const path of paths) { |
|
||||
const source = host.read(SOLUTION_TSCONFIG_PATH); |
|
||||
if (!source) { |
|
||||
// Solution tsconfig doesn't exist.
|
|
||||
logger.warn( |
|
||||
`Cannot add reference '${path}' in '${SOLUTION_TSCONFIG_PATH}'. File doesn't exists.`, |
|
||||
); |
|
||||
|
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
const jsonAst = parseJsonAst(source.toString(), JsonParseMode.Loose); |
|
||||
if (jsonAst?.kind !== 'object') { |
|
||||
// Invalid JSON
|
|
||||
throw new SchematicsException(`Invalid JSON AST Object '${SOLUTION_TSCONFIG_PATH}'.`); |
|
||||
} |
|
||||
|
|
||||
// Solutions style tsconfig can contain 2 properties:
|
|
||||
// - 'files' with a value of empty array
|
|
||||
// - 'references'
|
|
||||
const filesAst = findPropertyInAstObject(jsonAst, 'files'); |
|
||||
const referencesAst = findPropertyInAstObject(jsonAst, 'references'); |
|
||||
if ( |
|
||||
filesAst?.kind !== 'array' || |
|
||||
filesAst.elements.length !== 0 || |
|
||||
referencesAst?.kind !== 'array' |
|
||||
) { |
|
||||
logger.warn( |
|
||||
`Cannot add reference '${path}' in '${SOLUTION_TSCONFIG_PATH}'. It appears to be an invalid solution style tsconfig.`, |
|
||||
); |
|
||||
|
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
// Append new paths
|
|
||||
const recorder = host.beginUpdate(SOLUTION_TSCONFIG_PATH); |
|
||||
appendValueInAstArray(recorder, referencesAst, { path: `./${path}` }, 4); |
|
||||
host.commitUpdate(recorder); |
|
||||
} |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Throws an exception when the base tsconfig doesn't exists. |
|
||||
*/ |
|
||||
export function verifyBaseTsConfigExists(host: Tree): void { |
|
||||
if (host.exists('tsconfig.json')) { |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
throw new SchematicsException( |
|
||||
`Cannot find base TypeScript configuration file 'tsconfig.json'.`, |
|
||||
); |
|
||||
} |
|
||||
@ -0,0 +1,9 @@ |
|||||
|
import { Tree } from '@angular-devkit/schematics'; |
||||
|
import { resolveProject } from "./workspace"; |
||||
|
export async function createTargetLibIfNotExist(tree: Tree, target: string) { |
||||
|
const lib = await resolveProject(tree, target, null); |
||||
|
|
||||
|
if (!lib) { |
||||
|
|
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue