@schematics/angular 21.0.0-next.0 → 21.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/ai-config/index.js +5 -3
  2. package/ai-config/schema.json +1 -17
  3. package/app-shell/index.d.ts +2 -1
  4. package/app-shell/index.js +16 -24
  5. package/application/index.js +29 -1
  6. package/application/schema.d.ts +19 -1
  7. package/application/schema.js +13 -1
  8. package/application/schema.json +12 -2
  9. package/collection.json +7 -0
  10. package/component/files/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize__.spec.ts.template +6 -6
  11. package/component/files/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize__.ts.template +1 -1
  12. package/component/index.d.ts +2 -1
  13. package/component/index.js +49 -53
  14. package/component/schema.d.ts +5 -0
  15. package/component/schema.json +5 -0
  16. package/config/index.d.ts +2 -1
  17. package/config/index.js +12 -19
  18. package/directive/files/__name@dasherize__.__type@dasherize__.spec.ts.template +3 -3
  19. package/directive/files/__name@dasherize__.__type@dasherize__.ts.template +1 -1
  20. package/directive/index.d.ts +2 -1
  21. package/directive/index.js +25 -27
  22. package/directive/schema.d.ts +5 -0
  23. package/directive/schema.json +5 -0
  24. package/migrations/karma/karma-config-comparer.js +1 -1
  25. package/migrations/migration-collection.json +1 -0
  26. package/module/index.d.ts +2 -1
  27. package/module/index.js +48 -50
  28. package/ng-new/index.js +1 -0
  29. package/ng-new/schema.d.ts +19 -2
  30. package/ng-new/schema.js +13 -2
  31. package/ng-new/schema.json +8 -2
  32. package/package.json +4 -4
  33. package/pipe/index.d.ts +2 -2
  34. package/pipe/index.js +16 -18
  35. package/server/index.d.ts +2 -1
  36. package/server/index.js +67 -71
  37. package/service/files/__name@dasherize__.__type@dasherize__.spec.ts.template +4 -4
  38. package/service/files/__name@dasherize__.__type@dasherize__.ts.template +1 -1
  39. package/service/index.d.ts +2 -1
  40. package/service/index.js +20 -4
  41. package/service/schema.d.ts +5 -0
  42. package/service/schema.json +5 -0
  43. package/service-worker/index.d.ts +2 -1
  44. package/service-worker/index.js +44 -81
  45. package/ssr/index.d.ts +2 -1
  46. package/ssr/index.js +32 -40
  47. package/tailwind/files/.postcssrc.json.template +5 -0
  48. package/tailwind/index.d.ts +12 -0
  49. package/tailwind/index.js +105 -0
  50. package/tailwind/schema.d.ts +7 -0
  51. package/tailwind/schema.js +4 -0
  52. package/tailwind/schema.json +15 -0
  53. package/utility/ast-utils.js +31 -17
  54. package/utility/generate-from-files.d.ts +1 -0
  55. package/utility/latest-versions/package.json +3 -1
  56. package/utility/latest-versions.js +3 -3
  57. package/utility/project.d.ts +25 -0
  58. package/utility/project.js +30 -0
  59. package/utility/standalone/rules.js +2 -3
  60. package/web-worker/index.d.ts +2 -1
  61. package/web-worker/index.js +60 -70
  62. package/workspace/schema.d.ts +0 -1
  63. package/workspace/schema.js +0 -1
  64. package/workspace/schema.json +1 -1
  65. /package/application/files/common-files/src/app/{app.html.template → app__suffix__.html.template} +0 -0
  66. /package/application/files/module-files/src/app/{app.spec.ts.template → app__suffix__.spec.ts.template} +0 -0
  67. /package/application/files/module-files/src/app/{app.ts.template → app__suffix__.ts.template} +0 -0
  68. /package/application/files/standalone-files/src/app/{app.spec.ts.template → app__suffix__.spec.ts.template} +0 -0
  69. /package/application/files/standalone-files/src/app/{app.ts.template → app__suffix__.ts.template} +0 -0
@@ -1,13 +1,13 @@
1
1
  import { TestBed } from '@angular/core/testing';
2
2
 
3
- import { <%= classify(name) %><%= classify(type) %> } from './<%= dasherize(name) %><%= type ? '.' + dasherize(type) : '' %>';
3
+ import { <%= classifiedName %> } from './<%= dasherize(name) %><%= type ? '.' + dasherize(type) : '' %>';
4
4
 
5
- describe('<%= classify(name) %><%= classify(type) %>', () => {
6
- let service: <%= classify(name) %><%= classify(type) %>;
5
+ describe('<%= classifiedName %>', () => {
6
+ let service: <%= classifiedName %>;
7
7
 
8
8
  beforeEach(() => {
9
9
  TestBed.configureTestingModule({});
10
- service = TestBed.inject(<%= classify(name) %><%= classify(type) %>);
10
+ service = TestBed.inject(<%= classifiedName %>);
11
11
  });
12
12
 
13
13
  it('should be created', () => {
@@ -3,6 +3,6 @@ import { Injectable } from '@angular/core';
3
3
  @Injectable({
4
4
  providedIn: 'root'
5
5
  })
6
- export class <%= classify(name) %><%= classify(type) %> {
6
+ export class <%= classifiedName %> {
7
7
 
8
8
  }
@@ -7,4 +7,5 @@
7
7
  */
8
8
  import { Rule } from '@angular-devkit/schematics';
9
9
  import { Schema as ServiceOptions } from './schema';
10
- export default function (options: ServiceOptions): Rule;
10
+ declare const _default: (options: ServiceOptions) => Rule;
11
+ export default _default;
package/service/index.js CHANGED
@@ -7,8 +7,24 @@
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.default = default_1;
10
+ const schematics_1 = require("@angular-devkit/schematics");
11
11
  const generate_from_files_1 = require("../utility/generate-from-files");
12
- function default_1(options) {
13
- return (0, generate_from_files_1.generateFromFiles)(options);
14
- }
12
+ const parse_name_1 = require("../utility/parse-name");
13
+ const project_1 = require("../utility/project");
14
+ const validation_1 = require("../utility/validation");
15
+ const workspace_1 = require("../utility/workspace");
16
+ exports.default = (0, project_1.createProjectSchematic)((options, { project, tree }) => {
17
+ if (options.path === undefined) {
18
+ options.path = (0, workspace_1.buildDefaultPath)(project);
19
+ }
20
+ const parsedPath = (0, parse_name_1.parseName)(options.path, options.name);
21
+ options.name = parsedPath.name;
22
+ options.path = parsedPath.path;
23
+ const classifiedName = schematics_1.strings.classify(options.name) +
24
+ (options.addTypeToClassName && options.type ? schematics_1.strings.classify(options.type) : '');
25
+ (0, validation_1.validateClassName)(classifiedName);
26
+ return (0, generate_from_files_1.generateFromFiles)({
27
+ ...options,
28
+ classifiedName,
29
+ });
30
+ });
@@ -4,6 +4,11 @@
4
4
  * process of generating a new service with the necessary files and boilerplate code.
5
5
  */
6
6
  export type Schema = {
7
+ /**
8
+ * When true, the 'type' option will be appended to the generated class name. When false,
9
+ * only the file name will include the type.
10
+ */
11
+ addTypeToClassName?: boolean;
7
12
  /**
8
13
  * Creates files at the top level of the project or the given path. If set to false, a new
9
14
  * folder with the service's name will be created to contain the files.
@@ -43,6 +43,11 @@
43
43
  "type": {
44
44
  "type": "string",
45
45
  "description": "Append a custom type to the service's filename. For example, if you set the type to `service`, the file will be named `my-service.service.ts`."
46
+ },
47
+ "addTypeToClassName": {
48
+ "type": "boolean",
49
+ "default": true,
50
+ "description": "When true, the 'type' option will be appended to the generated class name. When false, only the file name will include the type."
46
51
  }
47
52
  },
48
53
  "required": ["name", "project"]
@@ -7,4 +7,5 @@
7
7
  */
8
8
  import { Rule } from '@angular-devkit/schematics';
9
9
  import { Schema as ServiceWorkerOptions } from './schema';
10
- export default function (options: ServiceWorkerOptions): Rule;
10
+ declare const _default: (options: ServiceWorkerOptions) => Rule;
11
+ export default _default;
@@ -6,50 +6,20 @@
6
6
  * Use of this source code is governed by an MIT-style license that can be
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- var desc = Object.getOwnPropertyDescriptor(m, k);
12
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
- desc = { enumerable: true, get: function() { return m[k]; } };
14
- }
15
- Object.defineProperty(o, k2, desc);
16
- }) : (function(o, m, k, k2) {
17
- if (k2 === undefined) k2 = k;
18
- o[k2] = m[k];
19
- }));
20
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
- Object.defineProperty(o, "default", { enumerable: true, value: v });
22
- }) : function(o, v) {
23
- o["default"] = v;
24
- });
25
- var __importStar = (this && this.__importStar) || (function () {
26
- var ownKeys = function(o) {
27
- ownKeys = Object.getOwnPropertyNames || function (o) {
28
- var ar = [];
29
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
- return ar;
31
- };
32
- return ownKeys(o);
33
- };
34
- return function (mod) {
35
- if (mod && mod.__esModule) return mod;
36
- var result = {};
37
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
- __setModuleDefault(result, mod);
39
- return result;
40
- };
41
- })();
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
42
12
  Object.defineProperty(exports, "__esModule", { value: true });
43
- exports.default = default_1;
44
- const core_1 = require("@angular-devkit/core");
45
13
  const schematics_1 = require("@angular-devkit/schematics");
46
- const ts = __importStar(require("../third_party/github.com/Microsoft/TypeScript/lib/typescript"));
14
+ const posix_1 = require("node:path/posix");
15
+ const typescript_1 = __importDefault(require("../third_party/github.com/Microsoft/TypeScript/lib/typescript"));
47
16
  const utility_1 = require("../utility");
48
17
  const ast_utils_1 = require("../utility/ast-utils");
49
18
  const change_1 = require("../utility/change");
50
19
  const dependency_1 = require("../utility/dependency");
51
20
  const ng_ast_utils_1 = require("../utility/ng-ast-utils");
52
21
  const paths_1 = require("../utility/paths");
22
+ const project_1 = require("../utility/project");
53
23
  const project_targets_1 = require("../utility/project-targets");
54
24
  const app_config_1 = require("../utility/standalone/app_config");
55
25
  const util_1 = require("../utility/standalone/util");
@@ -71,7 +41,7 @@ function updateAppModule(mainPath) {
71
41
  addImport(host, modulePath, 'ServiceWorkerModule', '@angular/service-worker');
72
42
  addImport(host, modulePath, 'isDevMode', '@angular/core');
73
43
  // register SW in application module
74
- const importText = core_1.tags.stripIndent `
44
+ const importText = `
75
45
  ServiceWorkerModule.register('ngsw-worker.js', {
76
46
  enabled: !isDevMode(),
77
47
  // Register the ServiceWorker as soon as the application is stable
@@ -102,53 +72,46 @@ function addProvideServiceWorker(projectName, mainPath) {
102
72
  }
103
73
  function getTsSourceFile(host, path) {
104
74
  const content = host.readText(path);
105
- const source = ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true);
75
+ const source = typescript_1.default.createSourceFile(path, content, typescript_1.default.ScriptTarget.Latest, true);
106
76
  return source;
107
77
  }
108
- function default_1(options) {
109
- return async (host) => {
110
- const workspace = await (0, utility_1.readWorkspace)(host);
111
- const project = workspace.projects.get(options.project);
112
- if (!project) {
113
- throw new schematics_1.SchematicsException(`Invalid project name (${options.project})`);
114
- }
115
- if (project.extensions.projectType !== 'application') {
116
- throw new schematics_1.SchematicsException(`Service worker requires a project type of "application".`);
117
- }
118
- const buildTarget = project.targets.get('build');
119
- if (!buildTarget) {
120
- throw (0, project_targets_1.targetBuildNotFoundError)();
121
- }
122
- const buildOptions = buildTarget.options;
123
- const browserEntryPoint = await (0, util_1.getMainFilePath)(host, options.project);
124
- const ngswConfigPath = (0, core_1.join)((0, core_1.normalize)(project.root), 'ngsw-config.json');
125
- if (buildTarget.builder === workspace_models_1.Builders.Application ||
126
- buildTarget.builder === workspace_models_1.Builders.BuildApplication) {
127
- const productionConf = buildTarget.configurations?.production;
128
- if (productionConf) {
129
- productionConf.serviceWorker = ngswConfigPath;
130
- }
131
- }
132
- else {
133
- buildOptions.serviceWorker = true;
134
- buildOptions.ngswConfigPath = ngswConfigPath;
78
+ exports.default = (0, project_1.createProjectSchematic)(async (options, { project, workspace, tree }) => {
79
+ if (project.extensions.projectType !== 'application') {
80
+ throw new schematics_1.SchematicsException(`Service worker requires a project type of "application".`);
81
+ }
82
+ const buildTarget = project.targets.get('build');
83
+ if (!buildTarget) {
84
+ throw (0, project_targets_1.targetBuildNotFoundError)();
85
+ }
86
+ const buildOptions = buildTarget.options;
87
+ const browserEntryPoint = await (0, util_1.getMainFilePath)(tree, options.project);
88
+ const ngswConfigPath = (0, posix_1.join)(project.root, 'ngsw-config.json');
89
+ if (buildTarget.builder === workspace_models_1.Builders.Application ||
90
+ buildTarget.builder === workspace_models_1.Builders.BuildApplication) {
91
+ const productionConf = buildTarget.configurations?.production;
92
+ if (productionConf) {
93
+ productionConf.serviceWorker = ngswConfigPath;
135
94
  }
136
- await (0, utility_1.writeWorkspace)(host, workspace);
137
- return (0, schematics_1.chain)([
138
- addDependencies(),
139
- (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files'), [
140
- (0, schematics_1.applyTemplates)({
141
- ...options,
142
- relativePathToWorkspaceRoot: (0, paths_1.relativePathToWorkspaceRoot)(project.root),
143
- }),
144
- (0, schematics_1.move)(project.root),
145
- ])),
146
- (0, ng_ast_utils_1.isStandaloneApp)(host, browserEntryPoint)
147
- ? addProvideServiceWorker(options.project, browserEntryPoint)
148
- : updateAppModule(browserEntryPoint),
149
- ]);
150
- };
151
- }
95
+ }
96
+ else {
97
+ buildOptions.serviceWorker = true;
98
+ buildOptions.ngswConfigPath = ngswConfigPath;
99
+ }
100
+ await (0, utility_1.writeWorkspace)(tree, workspace);
101
+ return (0, schematics_1.chain)([
102
+ addDependencies(),
103
+ (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files'), [
104
+ (0, schematics_1.applyTemplates)({
105
+ ...options,
106
+ relativePathToWorkspaceRoot: (0, paths_1.relativePathToWorkspaceRoot)(project.root),
107
+ }),
108
+ (0, schematics_1.move)(project.root),
109
+ ])),
110
+ (0, ng_ast_utils_1.isStandaloneApp)(tree, browserEntryPoint)
111
+ ? addProvideServiceWorker(options.project, browserEntryPoint)
112
+ : updateAppModule(browserEntryPoint),
113
+ ]);
114
+ });
152
115
  function addImport(host, filePath, symbolName, moduleName) {
153
116
  const moduleSource = getTsSourceFile(host, filePath);
154
117
  const change = (0, ast_utils_1.insertImport)(moduleSource, filePath, symbolName, moduleName);
package/ssr/index.d.ts CHANGED
@@ -7,4 +7,5 @@
7
7
  */
8
8
  import { Rule } from '@angular-devkit/schematics';
9
9
  import { Schema as SSROptions } from './schema';
10
- export default function (options: SSROptions): Rule;
10
+ declare const _default: (options: SSROptions) => Rule;
11
+ export default _default;
package/ssr/index.js CHANGED
@@ -7,17 +7,16 @@
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.default = default_1;
11
10
  const core_1 = require("@angular-devkit/core");
12
11
  const schematics_1 = require("@angular-devkit/schematics");
13
- const node_path_1 = require("node:path");
12
+ const posix_1 = require("node:path/posix");
14
13
  const utility_1 = require("../utility");
15
14
  const json_file_1 = require("../utility/json-file");
16
15
  const latest_versions_1 = require("../utility/latest-versions");
17
16
  const ng_ast_utils_1 = require("../utility/ng-ast-utils");
17
+ const project_1 = require("../utility/project");
18
18
  const project_targets_1 = require("../utility/project-targets");
19
19
  const util_1 = require("../utility/standalone/util");
20
- const workspace_1 = require("../utility/workspace");
21
20
  const SERVE_SSR_TARGET_NAME = 'serve-ssr';
22
21
  const PRERENDER_TARGET_NAME = 'prerender';
23
22
  const DEFAULT_BROWSER_DIR = 'browser';
@@ -48,7 +47,7 @@ async function getApplicationBuilderOutputPaths(host, projectName) {
48
47
  }
49
48
  let { outputPath } = architectTarget.options;
50
49
  // Use default if not explicitly specified
51
- outputPath ??= node_path_1.posix.join('dist', projectName);
50
+ outputPath ??= (0, posix_1.join)('dist', projectName);
52
51
  const defaultDirs = {
53
52
  server: DEFAULT_SERVER_DIR,
54
53
  browser: DEFAULT_BROWSER_DIR,
@@ -78,7 +77,7 @@ function addScriptsRule({ project }, isUsingApplicationBuilder) {
78
77
  if (isUsingApplicationBuilder) {
79
78
  const { base, server } = await getApplicationBuilderOutputPaths(host, project);
80
79
  pkg.scripts ??= {};
81
- pkg.scripts[`serve:ssr:${project}`] = `node ${node_path_1.posix.join(base, server)}/server.mjs`;
80
+ pkg.scripts[`serve:ssr:${project}`] = `node ${(0, posix_1.join)(base, server)}/server.mjs`;
82
81
  }
83
82
  else {
84
83
  const serverDist = await getLegacyOutputPaths(host, project, 'server');
@@ -128,7 +127,7 @@ function updateApplicationBuilderWorkspaceConfigRule(projectSourceRoot, options,
128
127
  if (outputPath && (0, core_1.isJsonObject)(outputPath)) {
129
128
  if (outputPath.browser === '') {
130
129
  const base = outputPath.base;
131
- logger.warn(`The output location of the browser build has been updated from "${base}" to "${node_path_1.posix.join(base, DEFAULT_BROWSER_DIR)}".
130
+ logger.warn(`The output location of the browser build has been updated from "${base}" to "${(0, posix_1.join)(base, DEFAULT_BROWSER_DIR)}".
132
131
  You might need to adjust your deployment pipeline.`);
133
132
  if ((outputPath.media && outputPath.media !== DEFAULT_MEDIA_DIR) ||
134
133
  (outputPath.server && outputPath.server !== DEFAULT_SERVER_DIR)) {
@@ -144,7 +143,7 @@ function updateApplicationBuilderWorkspaceConfigRule(projectSourceRoot, options,
144
143
  outputPath,
145
144
  outputMode: 'server',
146
145
  ssr: {
147
- entry: (0, core_1.join)((0, core_1.normalize)(projectSourceRoot), 'server.ts'),
146
+ entry: (0, posix_1.join)(projectSourceRoot, 'server.ts'),
148
147
  },
149
148
  };
150
149
  });
@@ -158,7 +157,7 @@ function updateWebpackBuilderWorkspaceConfigRule(projectSourceRoot, options) {
158
157
  }
159
158
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
160
159
  const serverTarget = project.targets.get('server');
161
- (serverTarget.options ??= {}).main = node_path_1.posix.join(projectSourceRoot, 'server.ts');
160
+ (serverTarget.options ??= {}).main = (0, posix_1.join)(projectSourceRoot, 'server.ts');
162
161
  const serveSSRTarget = project.targets.get(SERVE_SSR_TARGET_NAME);
163
162
  if (serveSSRTarget) {
164
163
  return;
@@ -260,7 +259,7 @@ function addServerFile(projectSourceRoot, options, isStandalone) {
260
259
  : await getLegacyOutputPaths(host, projectName, 'build');
261
260
  return (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)(`./files/${usingApplicationBuilder ? 'application-builder' : 'server-builder'}`), [
262
261
  (0, schematics_1.applyTemplates)({
263
- ...core_1.strings,
262
+ ...schematics_1.strings,
264
263
  ...options,
265
264
  browserDistDirectory,
266
265
  isStandalone,
@@ -269,34 +268,27 @@ function addServerFile(projectSourceRoot, options, isStandalone) {
269
268
  ]));
270
269
  };
271
270
  }
272
- function default_1(options) {
273
- return async (host, context) => {
274
- const browserEntryPoint = await (0, util_1.getMainFilePath)(host, options.project);
275
- const isStandalone = (0, ng_ast_utils_1.isStandaloneApp)(host, browserEntryPoint);
276
- const workspace = await (0, workspace_1.getWorkspace)(host);
277
- const clientProject = workspace.projects.get(options.project);
278
- if (!clientProject) {
279
- throw (0, project_targets_1.targetBuildNotFoundError)();
280
- }
281
- const usingApplicationBuilder = (0, project_targets_1.isUsingApplicationBuilder)(clientProject);
282
- const sourceRoot = clientProject.sourceRoot ?? node_path_1.posix.join(clientProject.root, 'src');
283
- return (0, schematics_1.chain)([
284
- (0, schematics_1.schematic)('server', {
285
- ...options,
286
- skipInstall: true,
287
- }),
288
- ...(usingApplicationBuilder
289
- ? [
290
- updateApplicationBuilderWorkspaceConfigRule(sourceRoot, options, context),
291
- updateApplicationBuilderTsConfigRule(options),
292
- ]
293
- : [
294
- updateWebpackBuilderServerTsConfigRule(options),
295
- updateWebpackBuilderWorkspaceConfigRule(sourceRoot, options),
296
- ]),
297
- addServerFile(sourceRoot, options, isStandalone),
298
- addScriptsRule(options, usingApplicationBuilder),
299
- addDependencies(options, usingApplicationBuilder),
300
- ]);
301
- };
302
- }
271
+ exports.default = (0, project_1.createProjectSchematic)(async (options, { project, tree, context }) => {
272
+ const browserEntryPoint = await (0, util_1.getMainFilePath)(tree, options.project);
273
+ const isStandalone = (0, ng_ast_utils_1.isStandaloneApp)(tree, browserEntryPoint);
274
+ const usingApplicationBuilder = (0, project_targets_1.isUsingApplicationBuilder)(project);
275
+ const sourceRoot = project.sourceRoot ?? (0, posix_1.join)(project.root, 'src');
276
+ return (0, schematics_1.chain)([
277
+ (0, schematics_1.schematic)('server', {
278
+ ...options,
279
+ skipInstall: true,
280
+ }),
281
+ ...(usingApplicationBuilder
282
+ ? [
283
+ updateApplicationBuilderWorkspaceConfigRule(sourceRoot, options, context),
284
+ updateApplicationBuilderTsConfigRule(options),
285
+ ]
286
+ : [
287
+ updateWebpackBuilderServerTsConfigRule(options),
288
+ updateWebpackBuilderWorkspaceConfigRule(sourceRoot, options),
289
+ ]),
290
+ addServerFile(sourceRoot, options, isStandalone),
291
+ addScriptsRule(options, usingApplicationBuilder),
292
+ addDependencies(options, usingApplicationBuilder),
293
+ ]);
294
+ });
@@ -0,0 +1,5 @@
1
+ {
2
+ "plugins": {
3
+ "@tailwindcss/postcss": {}
4
+ }
5
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ import { type Rule } from '@angular-devkit/schematics';
9
+ declare const _default: (options: {
10
+ project: string;
11
+ }) => Rule;
12
+ export default _default;
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.dev/license
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ const schematics_1 = require("@angular-devkit/schematics");
14
+ const node_assert_1 = __importDefault(require("node:assert"));
15
+ const posix_1 = require("node:path/posix");
16
+ const utility_1 = require("../utility");
17
+ const json_file_1 = require("../utility/json-file");
18
+ const latest_versions_1 = require("../utility/latest-versions");
19
+ const project_1 = require("../utility/project");
20
+ const TAILWIND_DEPENDENCIES = ['tailwindcss', '@tailwindcss/postcss', 'postcss'];
21
+ const POSTCSS_CONFIG_FILES = ['.postcssrc.json', 'postcss.config.json'];
22
+ function addTailwindStyles(options, project) {
23
+ return async (tree) => {
24
+ const buildTarget = project.targets.get('build');
25
+ if (!buildTarget) {
26
+ throw new schematics_1.SchematicsException(`Project "${options.project}" does not have a build target.`);
27
+ }
28
+ const styles = buildTarget.options?.['styles'];
29
+ let stylesheetPath;
30
+ if (styles) {
31
+ stylesheetPath = styles
32
+ .map((s) => (typeof s === 'string' ? s : s.input))
33
+ .find((p) => p.endsWith('.css'));
34
+ }
35
+ if (!stylesheetPath) {
36
+ const newStylesheetPath = (0, posix_1.join)(project.sourceRoot ?? 'src', 'tailwind.css');
37
+ tree.create(newStylesheetPath, '@import "tailwindcss";\n');
38
+ return (0, utility_1.updateWorkspace)((workspace) => {
39
+ const project = workspace.projects.get(options.project);
40
+ if (project) {
41
+ const buildTarget = project.targets.get('build');
42
+ (0, node_assert_1.default)(buildTarget, 'Build target should still be present');
43
+ // Update main styles
44
+ const buildOptions = buildTarget.options;
45
+ (0, node_assert_1.default)(buildOptions, 'Build options should still be present');
46
+ const existingStyles = buildOptions['styles'] ?? [];
47
+ buildOptions['styles'] = [newStylesheetPath, ...existingStyles];
48
+ // Update configuration styles
49
+ if (buildTarget.configurations) {
50
+ for (const config of Object.values(buildTarget.configurations)) {
51
+ if (config && 'styles' in config) {
52
+ const existingStyles = config['styles'] ?? [];
53
+ config['styles'] = [newStylesheetPath, ...existingStyles];
54
+ }
55
+ }
56
+ }
57
+ }
58
+ });
59
+ }
60
+ else {
61
+ let stylesheetContent = tree.readText(stylesheetPath);
62
+ if (!stylesheetContent.includes('@import "tailwindcss";')) {
63
+ stylesheetContent += '\n@import "tailwindcss";\n';
64
+ tree.overwrite(stylesheetPath, stylesheetContent);
65
+ }
66
+ }
67
+ };
68
+ }
69
+ function managePostCssConfiguration(project) {
70
+ return async (tree) => {
71
+ const searchPaths = ['/', project.root]; // Workspace root and project root
72
+ for (const path of searchPaths) {
73
+ for (const configFile of POSTCSS_CONFIG_FILES) {
74
+ const fullPath = (0, posix_1.join)(path, configFile);
75
+ if (tree.exists(fullPath)) {
76
+ const postcssConfig = new json_file_1.JSONFile(tree, fullPath);
77
+ const tailwindPluginPath = ['plugins', '@tailwindcss/postcss'];
78
+ if (postcssConfig.get(tailwindPluginPath) === undefined) {
79
+ postcssConfig.modify(tailwindPluginPath, {});
80
+ }
81
+ // Config found and handled
82
+ return;
83
+ }
84
+ }
85
+ }
86
+ // No existing config found, so create one from the template
87
+ const templateSource = (0, schematics_1.apply)((0, schematics_1.url)('./files'), [
88
+ (0, schematics_1.applyTemplates)({
89
+ ...schematics_1.strings,
90
+ }),
91
+ (0, schematics_1.move)(project.root),
92
+ ]);
93
+ return (0, schematics_1.mergeWith)(templateSource);
94
+ };
95
+ }
96
+ exports.default = (0, project_1.createProjectSchematic)((options, { project }) => {
97
+ return (0, schematics_1.chain)([
98
+ addTailwindStyles(options, project),
99
+ managePostCssConfiguration(project),
100
+ ...TAILWIND_DEPENDENCIES.map((name) => (0, utility_1.addDependency)(name, latest_versions_1.latestVersions[name], {
101
+ type: utility_1.DependencyType.Dev,
102
+ existing: utility_1.ExistingBehavior.Skip,
103
+ })),
104
+ ]);
105
+ });
@@ -0,0 +1,7 @@
1
+ export type Schema = {
2
+ /**
3
+ * The name of the project.
4
+ */
5
+ project: string;
6
+ [property: string]: any;
7
+ };
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ // THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
3
+ // CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
4
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema",
3
+ "title": "Tailwind CSS Schematic",
4
+ "type": "object",
5
+ "properties": {
6
+ "project": {
7
+ "type": "string",
8
+ "description": "The name of the project.",
9
+ "$default": {
10
+ "$source": "projectName"
11
+ }
12
+ }
13
+ },
14
+ "required": ["project"]
15
+ }