Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/angular/ssr/src/app-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class AngularAppEngine {
*
* @private
*/
static ɵhooks = /* #__PURE__*/ new Hooks();
static ɵhooks: Hooks = /* #__PURE__*/ new Hooks();

/**
* The manifest for the server application.
Expand Down
4 changes: 3 additions & 1 deletion packages/angular/ssr/src/routes/route-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ export class RouteTree<AdditionalMetadata extends Record<string, unknown> = {}>
*
* @param node - The current node to start the traversal from. Defaults to the root node of the tree.
*/
*traverse(node = this.root): Generator<RouteTreeNodeMetadata & AdditionalMetadata> {
*traverse(
node: RouteTreeNode<AdditionalMetadata> = this.root,
): Generator<RouteTreeNodeMetadata & AdditionalMetadata> {
if (node.metadata) {
yield node.metadata;
}
Expand Down
45 changes: 28 additions & 17 deletions packages/schematics/angular/app-shell/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
* found in the LICENSE file at https://angular.dev/license
*/

import { Rule, SchematicsException, Tree, chain, schematic } from '@angular-devkit/schematics';
import {
Rule,
RuleFactory,
SchematicsException,
Tree,
chain,
schematic,
} from '@angular-devkit/schematics';
import { dirname, join } from 'node:path/posix';
import ts from '../third_party/github.com/Microsoft/TypeScript/lib/typescript';
import {
Expand Down Expand Up @@ -190,19 +197,23 @@ function addServerRoutingConfig(options: AppShellOptions, isStandalone: boolean)
};
}

export default createProjectSchematic<AppShellOptions>(async (options, { tree }) => {
const browserEntryPoint = await getMainFilePath(tree, options.project);
const isStandalone = isStandaloneApp(tree, browserEntryPoint);

return chain([
validateProject(browserEntryPoint),
schematic('server', options),
addServerRoutingConfig(options, isStandalone),
schematic('component', {
name: 'app-shell',
module: 'app.module.server.ts',
project: options.project,
standalone: isStandalone,
}),
]);
});
const appShellSchematic: RuleFactory<AppShellOptions> = createProjectSchematic(
async (options, { tree }) => {
const browserEntryPoint = await getMainFilePath(tree, options.project);
const isStandalone = isStandaloneApp(tree, browserEntryPoint);

return chain([
validateProject(browserEntryPoint),
schematic('server', options),
addServerRoutingConfig(options, isStandalone),
schematic('component', {
name: 'app-shell',
module: 'app.module.server.ts',
project: options.project,
standalone: isStandalone,
}),
]);
},
);

export default appShellSchematic;
109 changes: 57 additions & 52 deletions packages/schematics/angular/component/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {
FileOperator,
Rule,
RuleFactory,
apply,
applyTemplates,
chain,
Expand Down Expand Up @@ -40,60 +40,65 @@ function buildSelector(options: ComponentOptions, projectPrefix: string) {
return selector;
}

export default createProjectSchematic<ComponentOptions>((options, { project, tree }) => {
if (options.path === undefined) {
options.path = buildDefaultPath(project);
}
const componentSchematic: RuleFactory<ComponentOptions> = createProjectSchematic(
(options, { project, tree }) => {
if (options.path === undefined) {
options.path = buildDefaultPath(project);
}

options.module = findModuleFromOptions(tree, options);
// Schematic templates require a defined type value
options.type ??= '';

options.module = findModuleFromOptions(tree, options);
// Schematic templates require a defined type value
options.type ??= '';
const parsedPath = parseName(options.path, options.name);
options.name = parsedPath.name;
options.path = parsedPath.path;
options.selector =
options.selector || buildSelector(options, (project && project.prefix) || '');

const parsedPath = parseName(options.path, options.name);
options.name = parsedPath.name;
options.path = parsedPath.path;
options.selector = options.selector || buildSelector(options, (project && project.prefix) || '');
validateHtmlSelector(options.selector);

validateHtmlSelector(options.selector);
const classifiedName =
strings.classify(options.name) +
(options.addTypeToClassName && options.type ? strings.classify(options.type) : '');
validateClassName(classifiedName);
const zoneless = isZonelessApp(project);

const classifiedName =
strings.classify(options.name) +
(options.addTypeToClassName && options.type ? strings.classify(options.type) : '');
validateClassName(classifiedName);
const zoneless = isZonelessApp(project);
const skipStyleFile = options.inlineStyle || options.style === Style.None;
const templateSource = apply(url('./files'), [
options.skipTests ? filter((path) => !path.endsWith('.spec.ts.template')) : noop(),
skipStyleFile ? filter((path) => !path.endsWith('.__style__.template')) : noop(),
options.inlineTemplate ? filter((path) => !path.endsWith('.html.template')) : noop(),
applyTemplates({
...strings,
'if-flat': (s: string) => (options.flat ? '' : s),
'ngext': options.ngHtml ? '.ng' : '',
...options,
// Add a new variable for the classified name, conditionally including the type
classifiedName,
zoneless,
}),
!options.type
? forEach(((file) => {
return file.path.includes('..')
? {
content: file.content,
path: file.path.replace('..', '.'),
}
: file;
}) as FileOperator)
: noop(),
move(parsedPath.path),
]);

const skipStyleFile = options.inlineStyle || options.style === Style.None;
const templateSource = apply(url('./files'), [
options.skipTests ? filter((path) => !path.endsWith('.spec.ts.template')) : noop(),
skipStyleFile ? filter((path) => !path.endsWith('.__style__.template')) : noop(),
options.inlineTemplate ? filter((path) => !path.endsWith('.html.template')) : noop(),
applyTemplates({
...strings,
'if-flat': (s: string) => (options.flat ? '' : s),
'ngext': options.ngHtml ? '.ng' : '',
...options,
// Add a new variable for the classified name, conditionally including the type
classifiedName,
zoneless,
}),
!options.type
? forEach(((file) => {
return file.path.includes('..')
? {
content: file.content,
path: file.path.replace('..', '.'),
}
: file;
}) as FileOperator)
: noop(),
move(parsedPath.path),
]);
return chain([
addDeclarationToNgModule({
type: 'component',
...options,
}),
mergeWith(templateSource),
]);
},
);

return chain([
addDeclarationToNgModule({
type: 'component',
...options,
}),
mergeWith(templateSource),
]);
});
export default componentSchematic;
29 changes: 17 additions & 12 deletions packages/schematics/angular/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import {
Rule,
RuleFactory,
SchematicsException,
apply,
applyTemplates,
Expand All @@ -24,18 +25,22 @@ import { updateWorkspace } from '../utility/workspace';
import { Builders as AngularBuilder } from '../utility/workspace-models';
import { Schema as ConfigOptions, Type as ConfigType } from './schema';

export default createProjectSchematic<ConfigOptions>((options, { project }) => {
switch (options.type) {
case ConfigType.Karma:
return addKarmaConfig(options);
case ConfigType.Browserslist:
return addBrowserslistConfig(project.root);
case ConfigType.Vitest:
return addVitestConfig(options);
default:
throw new SchematicsException(`"${options.type}" is an unknown configuration file type.`);
}
});
const configSchematic: RuleFactory<ConfigOptions> = createProjectSchematic(
(options, { project }) => {
switch (options.type) {
case ConfigType.Karma:
return addKarmaConfig(options);
case ConfigType.Browserslist:
return addBrowserslistConfig(project.root);
case ConfigType.Vitest:
return addVitestConfig(options);
default:
throw new SchematicsException(`"${options.type}" is an unknown configuration file type.`);
}
},
);

export default configSchematic;

function addVitestConfig(options: ConfigOptions): Rule {
return (tree, context) =>
Expand Down
64 changes: 34 additions & 30 deletions packages/schematics/angular/directive/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

import { Rule, chain, strings } from '@angular-devkit/schematics';
import { RuleFactory, chain, strings } from '@angular-devkit/schematics';
import { addDeclarationToNgModule } from '../utility/add-declaration-to-ng-module';
import { findModuleFromOptions } from '../utility/find-module';
import { generateFromFiles } from '../utility/generate-from-files';
Expand All @@ -27,32 +27,36 @@ function buildSelector(options: DirectiveOptions, projectPrefix: string) {
return strings.camelize(selector);
}

export default createProjectSchematic<DirectiveOptions>((options, { project, tree }) => {
if (options.path === undefined) {
options.path = buildDefaultPath(project);
}

options.module = findModuleFromOptions(tree, options);
const parsedPath = parseName(options.path, options.name);
options.name = parsedPath.name;
options.path = parsedPath.path;
options.selector = options.selector || buildSelector(options, project.prefix || '');

validateHtmlSelector(options.selector);
const classifiedName =
strings.classify(options.name) +
(options.addTypeToClassName && options.type ? strings.classify(options.type) : '');
validateClassName(classifiedName);

return chain([
addDeclarationToNgModule({
type: 'directive',

...options,
}),
generateFromFiles({
...options,
classifiedName,
}),
]);
});
const directiveSchematic: RuleFactory<DirectiveOptions> = createProjectSchematic(
(options, { project, tree }) => {
if (options.path === undefined) {
options.path = buildDefaultPath(project);
}

options.module = findModuleFromOptions(tree, options);
const parsedPath = parseName(options.path, options.name);
options.name = parsedPath.name;
options.path = parsedPath.path;
options.selector = options.selector || buildSelector(options, project.prefix || '');

validateHtmlSelector(options.selector);
const classifiedName =
strings.classify(options.name) +
(options.addTypeToClassName && options.type ? strings.classify(options.type) : '');
validateClassName(classifiedName);

return chain([
addDeclarationToNgModule({
type: 'directive',

...options,
}),
generateFromFiles({
...options,
classifiedName,
}),
]);
},
);

export default directiveSchematic;
Loading