@salesforce/ui-bundle-template-app-angular-template-b2x 11.40.0 → 11.42.0

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.
package/dist/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [11.42.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.41.0...v11.42.0) (2026-07-27)
7
+
8
+ **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
9
+
10
+
11
+
12
+
13
+
14
+ ## [11.41.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.40.0...v11.41.0) (2026-07-24)
15
+
16
+ **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
17
+
18
+
19
+
20
+
21
+
6
22
  ## [11.40.0](https://github.com/salesforce-experience-platform-emu/webapps/compare/v11.39.0...v11.40.0) (2026-07-24)
7
23
 
8
24
  **Note:** Version bump only for package @salesforce/ui-bundle-template-base-sfdx-project
@@ -94,7 +94,7 @@
94
94
  "lint": {
95
95
  "builder": "@angular-eslint/builder:lint",
96
96
  "options": {
97
- "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
97
+ "lintFilePatterns": ["src/**/*.ts", "src/**/*.html", "src/**/*.graphql"]
98
98
  }
99
99
  }
100
100
  }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * eslint-plugin-angular-graphql.js
3
+ *
4
+ * Custom ESLint plugin with composite processor that enables BOTH:
5
+ * - Angular inline template linting (processInlineTemplates)
6
+ * - GraphQL tagged template literal linting (@graphql-eslint processor)
7
+ *
8
+ * ESLint only allows one processor per file type. This plugin calls both
9
+ * processors under the hood, returning the source code only once to avoid
10
+ * duplicate TypeScript lint messages.
11
+ *
12
+ * Usage:
13
+ * import { createPlugin } from './eslint-plugin-angular-graphql.js';
14
+ * const plugin = createPlugin({ schemaPath: '/absolute/path/to/schema.graphql' });
15
+ *
16
+ * Safety assumptions (verified against source):
17
+ * - Neither processor clones source messages in postprocess (object identity dedup works)
18
+ * - gql tags do not appear inside inline template strings (autofix ranges non-overlapping)
19
+ * - Both processors store internal state keyed by filePath (or derived from it)
20
+ */
21
+ import { existsSync } from 'node:fs';
22
+ import angular from 'angular-eslint';
23
+ import graphqlPlugin from '@graphql-eslint/eslint-plugin';
24
+
25
+ const angularProcessor = angular.processInlineTemplates;
26
+ const graphqlProcessor = graphqlPlugin.processor;
27
+
28
+ // Track block counts per file for postprocess message routing
29
+ const blockCountsMap = new Map();
30
+
31
+ const compositeProcessor = {
32
+ meta: {
33
+ name: 'angular-graphql/composite',
34
+ version: '1.0.0',
35
+ },
36
+ supportsAutofix: true,
37
+
38
+ preprocess(code, filePath) {
39
+ // Call both preprocessors — this populates their internal state maps
40
+ // Angular returns: [source, ...htmlBlocks] (source FIRST)
41
+ const angularResult = angularProcessor.preprocess(code, filePath);
42
+ // GraphQL returns: [...gqlBlocks, source] (source LAST)
43
+ const graphqlResult = graphqlProcessor.preprocess(code, filePath);
44
+
45
+ // Extract blocks (excluding source) from each
46
+ const htmlBlocks = angularResult.length > 1 ? angularResult.slice(1) : [];
47
+ const gqlBlocks = graphqlResult.length > 1 ? graphqlResult.slice(0, -1) : [];
48
+
49
+ // Store counts for postprocess routing
50
+ blockCountsMap.set(filePath, {
51
+ gqlCount: gqlBlocks.length,
52
+ htmlCount: htmlBlocks.length,
53
+ });
54
+
55
+ // Return unified: [gqlBlocks..., htmlBlocks..., source]
56
+ // Source appears exactly ONCE at the end
57
+ return [...gqlBlocks, ...htmlBlocks, code];
58
+ },
59
+
60
+ postprocess(messages, filePath) {
61
+ const { gqlCount, htmlCount } = blockCountsMap.get(filePath) || { gqlCount: 0, htmlCount: 0 };
62
+ blockCountsMap.delete(filePath);
63
+
64
+ const sourceIndex = gqlCount + htmlCount;
65
+ const sourceMessages = messages[sourceIndex] || [];
66
+
67
+ // Short-circuit: neither processor extracted blocks
68
+ if (gqlCount === 0 && htmlCount === 0) {
69
+ return sourceMessages;
70
+ }
71
+
72
+ // Short-circuit: only Angular had blocks
73
+ if (gqlCount === 0) {
74
+ const angularMessages = [sourceMessages, ...messages.slice(0, htmlCount)];
75
+ return angularProcessor.postprocess(angularMessages, filePath);
76
+ }
77
+
78
+ // Short-circuit: only GraphQL had blocks
79
+ if (htmlCount === 0) {
80
+ const gqlMessages = [...messages.slice(0, gqlCount), sourceMessages];
81
+ return graphqlProcessor.postprocess(gqlMessages, filePath);
82
+ }
83
+
84
+ // Both had blocks — route to each postprocess and merge
85
+ // GraphQL expects: [gqlBlock0Msgs, ..., gqlBlockNMsgs, sourceMessages]
86
+ const gqlInput = [...messages.slice(0, gqlCount), sourceMessages];
87
+ const gqlResult = graphqlProcessor.postprocess(gqlInput, filePath);
88
+
89
+ // Angular expects: [sourceMessages, htmlBlock0Msgs, ..., htmlBlockMMsgs]
90
+ const angularInput = [sourceMessages, ...messages.slice(gqlCount, gqlCount + htmlCount)];
91
+ const angularResult = angularProcessor.postprocess(angularInput, filePath);
92
+
93
+ // Deduplicate source messages (both postprocessors pass them through by reference)
94
+ const sourceSet = new Set(sourceMessages);
95
+ const gqlOnly = gqlResult.filter((m) => !sourceSet.has(m));
96
+
97
+ // angularResult = [...sourceMessages, ...adjustedHtmlMessages]
98
+ // gqlOnly = [...adjustedGqlMessages] (source messages filtered out)
99
+ return [...angularResult, ...gqlOnly].sort((a, b) => a.line - b.line || a.column - b.column);
100
+ },
101
+ };
102
+
103
+ /**
104
+ * Factory: pass schemaPath, get back a plugin with configs ready to spread.
105
+ * - If schema exists → composite processor (Angular + GraphQL) + GraphQL rules
106
+ * - If no schema → Angular-only inline template processor, no GraphQL rules
107
+ */
108
+ export function createPlugin({ schemaPath } = {}) {
109
+ const schemaExists = !!(schemaPath && existsSync(schemaPath));
110
+
111
+ const configs = [
112
+ {
113
+ files: ['**/*.ts'],
114
+ processor: schemaExists ? compositeProcessor : angularProcessor,
115
+ },
116
+ ...(schemaExists
117
+ ? [
118
+ {
119
+ files: ['**/*.graphql'],
120
+ languageOptions: {
121
+ parser: graphqlPlugin.parser,
122
+ parserOptions: {
123
+ graphQLConfig: {
124
+ schema: schemaPath,
125
+ documents: 'src/**/*.ts',
126
+ },
127
+ },
128
+ },
129
+ plugins: {
130
+ '@graphql-eslint': graphqlPlugin,
131
+ },
132
+ rules: {
133
+ '@graphql-eslint/no-anonymous-operations': 'error',
134
+ '@graphql-eslint/no-duplicate-fields': 'error',
135
+ '@graphql-eslint/known-fragment-names': 'error',
136
+ '@graphql-eslint/no-undefined-variables': 'error',
137
+ '@graphql-eslint/no-unused-variables': 'error',
138
+ },
139
+ },
140
+ ]
141
+ : []),
142
+ ];
143
+
144
+ return {
145
+ meta: { name: 'eslint-plugin-angular-graphql', version: '1.0.0' },
146
+ configs,
147
+ };
148
+ }
@@ -1,6 +1,13 @@
1
+ import { dirname, resolve } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
1
3
  import js from '@eslint/js';
2
4
  import angular from 'angular-eslint';
3
5
  import tseslint from 'typescript-eslint';
6
+ import { createPlugin } from './eslint-plugin-angular-graphql.js';
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const schemaPath = resolve(__dirname, '../../../../../schema.graphql');
10
+ const angularGraphqlPlugin = createPlugin({ schemaPath });
4
11
 
5
12
  export default tseslint.config(
6
13
  // Global ignores
@@ -15,7 +22,6 @@ export default tseslint.config(
15
22
  ...tseslint.configs.recommended,
16
23
  ...angular.configs.tsRecommended,
17
24
  ],
18
- processor: angular.processInlineTemplates,
19
25
  rules: {
20
26
  '@angular-eslint/directive-selector': [
21
27
  'error',
@@ -57,4 +63,6 @@ export default tseslint.config(
57
63
  extends: [...angular.configs.templateRecommended, ...angular.configs.templateAccessibility],
58
64
  rules: {},
59
65
  },
66
+ // Inline template processor + GraphQL rules (plugin handles schema detection)
67
+ ...angularGraphqlPlugin.configs,
60
68
  );
@@ -40,6 +40,7 @@
40
40
  "@angular/cli": "^21.2.11",
41
41
  "@angular/compiler-cli": "^21.2.0",
42
42
  "@eslint/js": "^9.0.0",
43
+ "@graphql-eslint/eslint-plugin": "^4.1.0",
43
44
  "@playwright/test": "^1.49.0",
44
45
  "@tailwindcss/postcss": "^4.0.0",
45
46
  "angular-eslint": "^21.0.0",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@salesforce/ui-bundle-template-base-sfdx-project",
3
- "version": "11.40.0",
3
+ "version": "11.42.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@salesforce/ui-bundle-template-base-sfdx-project",
9
- "version": "11.40.0",
9
+ "version": "11.42.0",
10
10
  "license": "SEE LICENSE IN LICENSE.txt",
11
11
  "dependencies": {
12
12
  "fast-xml-parser": "^5.9.3",
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/ui-bundle-template-base-sfdx-project",
3
- "version": "11.40.0",
3
+ "version": "11.42.0",
4
4
  "description": "Base SFDX project template",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "publishConfig": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/ui-bundle-template-app-angular-template-b2x",
3
- "version": "11.40.0",
3
+ "version": "11.42.0",
4
4
  "description": "Salesforce Angular external app template",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "author": "",