@ethlete/components 1.0.0-next.32 → 1.0.0-next.33

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.
@@ -1,5 +1,15 @@
1
1
  {
2
2
  "generators": {
3
+ "migrate-query-error-labels": {
4
+ "factory": "./migrate-query-error-labels/migration",
5
+ "schema": "./migrate-query-error-labels/schema.json",
6
+ "description": "Find query-error usage affected by the English-only label default and report where German must be re-opted-in"
7
+ },
8
+ "migrate-rich-text-editor-link-editor": {
9
+ "factory": "./migrate-rich-text-editor-link-editor/migration",
10
+ "schema": "./migrate-rich-text-editor-link-editor/schema.json",
11
+ "description": "Find rich text editor usage that loses the link editor popover and report where to re-opt-in"
12
+ },
3
13
  "icons": {
4
14
  "factory": "./icons/generator",
5
15
  "schema": "./icons/schema.json",
@@ -0,0 +1,30 @@
1
+ import { getProjects, visitNotIgnoredFiles } from '@nx/devkit';
2
+ const stripTrailingSlash = (value) => (value.endsWith('/') ? value.slice(0, -1) : value);
3
+ export const createMigrationScope = (tree, options) => {
4
+ const roots = [];
5
+ for (const projectName of options.projects ?? []) {
6
+ const project = getProjects(tree).get(projectName);
7
+ if (!project) {
8
+ throw new Error(`Unknown project "${projectName}". Pass names as they appear in \`nx show projects\`, or use --include with a path prefix.`);
9
+ }
10
+ roots.push(stripTrailingSlash(project.root));
11
+ }
12
+ for (const includePath of options.include ?? []) {
13
+ roots.push(stripTrailingSlash(includePath));
14
+ }
15
+ if (roots.length === 0) {
16
+ return {
17
+ visit: (targetTree, callback) => visitNotIgnoredFiles(targetTree, '', callback),
18
+ describe: () => 'the whole workspace',
19
+ };
20
+ }
21
+ return {
22
+ visit: (targetTree, callback) => {
23
+ for (const root of roots) {
24
+ visitNotIgnoredFiles(targetTree, root, callback);
25
+ }
26
+ },
27
+ describe: () => roots.join(', '),
28
+ };
29
+ };
30
+ //# sourceMappingURL=migration-scope.js.map
@@ -0,0 +1,58 @@
1
+ import { formatFiles } from '@nx/devkit';
2
+ import { createMigrationScope } from './migration-scope.js';
3
+ import { scanQueryErrorLabelsInFile } from './query-error-labels.js';
4
+ export const QUERY_ERROR_LABELS_REPORT_PATH = 'query-error-labels-migration-tasks.md';
5
+ const renderReport = (tasks) => [
6
+ '# Query-error labels migration tasks',
7
+ '',
8
+ 'Query-error titles and fallback messages no longer switch to German automatically when the locale is a',
9
+ 'German one — the default is English-only, so an English-only app stops bundling the German status table.',
10
+ 'Whether to bring German back is a product decision no codemod can make, so the sites below were found but',
11
+ 'not changed.',
12
+ '',
13
+ 'If the app should keep the old locale-driven wording, add once, app-wide:',
14
+ '',
15
+ '```ts',
16
+ "import { provideQueryErrorLabels, queryErrorLabelsForLocale } from '@ethlete/components';",
17
+ '',
18
+ 'provideQueryErrorLabels(queryErrorLabelsForLocale);',
19
+ '```',
20
+ '',
21
+ 'For German unconditionally, pass `GERMAN_QUERY_ERROR_LABELS` instead. If the app is English-only (or already',
22
+ 'overrides the labels), there is nothing to do — delete this file.',
23
+ '',
24
+ ...tasks.map((task) => [`## \`${task.id}\``, '', `- ${task.file}:${task.line}`, `- ${task.message}`, ''].join('\n')),
25
+ ].join('\n');
26
+ export default async function migrateQueryErrorLabels(tree, schema) {
27
+ console.log('\n🔎 Scanning for query-error usage affected by the English-only label default...');
28
+ const scope = createMigrationScope(tree, schema);
29
+ console.log(` Scope: ${scope.describe()}`);
30
+ const tasks = [];
31
+ let hasLabelProvider = false;
32
+ scope.visit(tree, (filePath) => {
33
+ if (!/\.(ts|html)$/.test(filePath) || filePath.endsWith('.d.ts'))
34
+ return;
35
+ const content = tree.read(filePath, 'utf-8');
36
+ if (!content)
37
+ return;
38
+ const result = scanQueryErrorLabelsInFile(filePath, content);
39
+ tasks.push(...result.usages);
40
+ hasLabelProvider ||= result.hasLabelProvider;
41
+ });
42
+ if (hasLabelProvider) {
43
+ console.log(' ✓ Found a provideQueryErrorLabels call — the app already controls its wording.');
44
+ }
45
+ else if (tasks.length > 0) {
46
+ tree.write(QUERY_ERROR_LABELS_REPORT_PATH, renderReport(tasks));
47
+ }
48
+ if (!schema.skipFormat) {
49
+ await formatFiles(tree);
50
+ }
51
+ if (!hasLabelProvider && tasks.length > 0) {
52
+ console.log(`\n⚠️ ${tasks.length} site(s) use query-error without a label provider — see ${QUERY_ERROR_LABELS_REPORT_PATH}.`);
53
+ }
54
+ else {
55
+ console.log('\n✅ Nothing to do.');
56
+ }
57
+ }
58
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The query-error labels no longer resolve German automatically from the locale — the default is the
3
+ * English status tables only, and German is an explicit `provideQueryErrorLabels(queryErrorLabelsForLocale)`
4
+ * (or `GERMAN_QUERY_ERROR_LABELS`) opt-in. Whether an app wants German back is a product decision, so this
5
+ * migration only finds the affected sites and reports them; it rewrites nothing.
6
+ */
7
+ const USAGE_MARKERS = [
8
+ 'et-query-error',
9
+ 'etQueryError',
10
+ 'QueryErrorComponent',
11
+ 'QueryErrorDirective',
12
+ 'QUERY_ERROR_IMPORTS',
13
+ 'injectQueryErrorLabels',
14
+ ];
15
+ const OPT_IN_MARKER = 'provideQueryErrorLabels';
16
+ export const scanQueryErrorLabelsInFile = (filePath, content) => {
17
+ const usages = [];
18
+ const marker = USAGE_MARKERS.find((m) => content.includes(m));
19
+ if (marker) {
20
+ const line = content.slice(0, content.indexOf(marker)).split('\n').length;
21
+ usages.push({
22
+ id: `query-error-labels--${filePath.replace(/[^a-zA-Z0-9]+/g, '-')}`,
23
+ file: filePath,
24
+ line,
25
+ message: `Uses the query-error UI (\`${marker}\`). Its titles and fallback messages are English-only by default now.`,
26
+ });
27
+ }
28
+ return { usages, hasLabelProvider: content.includes(OPT_IN_MARKER) };
29
+ };
30
+ //# sourceMappingURL=query-error-labels.js.map
@@ -0,0 +1,26 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "$id": "migrate-query-error-labels",
4
+ "title": "Find apps affected by the query-error label default change (English-only)",
5
+ "type": "object",
6
+ "properties": {
7
+ "projects": {
8
+ "type": "array",
9
+ "items": { "type": "string" },
10
+ "description": "Nx projects to scan. Defaults to every project in the workspace.",
11
+ "alias": "project"
12
+ },
13
+ "include": {
14
+ "type": "array",
15
+ "items": { "type": "string" },
16
+ "description": "Path prefixes to scan, relative to the workspace root (e.g. 'apps/shop'). Unioned with `projects`.",
17
+ "alias": "includePath"
18
+ },
19
+ "skipFormat": {
20
+ "type": "boolean",
21
+ "description": "Skip formatting files after migration",
22
+ "default": false
23
+ }
24
+ },
25
+ "required": []
26
+ }
@@ -0,0 +1,57 @@
1
+ import { formatFiles } from '@nx/devkit';
2
+ import { createMigrationScope } from '../migrate-query-error-labels/migration-scope.js';
3
+ import { scanRichTextEditorLinkEditorInFile } from './rich-text-editor-link-editor.js';
4
+ export const RICH_TEXT_EDITOR_LINK_EDITOR_REPORT_PATH = 'rich-text-editor-link-editor-migration-tasks.md';
5
+ const renderReport = (tasks) => [
6
+ '# Rich text editor link editor migration tasks',
7
+ '',
8
+ 'The rich text editor no longer mounts the link editor popover. Its `link` tool now falls back to the',
9
+ "browser's `prompt()`, so an editor that never opts in stops bundling the popover (and the form",
10
+ 'controls and overlay strategies it pulls in).',
11
+ '',
12
+ 'To keep the popover, add once — app-wide, or on the component/route that renders the editor:',
13
+ '',
14
+ '```ts',
15
+ "import { provideRichTextEditorLinkEditor } from '@ethlete/components';",
16
+ '',
17
+ 'provideRichTextEditorLinkEditor();',
18
+ '```',
19
+ '',
20
+ 'If the prompt fallback is fine (or the app never uses the `link` tool), there is nothing to do — delete',
21
+ 'this file.',
22
+ '',
23
+ ...tasks.map((task) => [`## \`${task.id}\``, '', `- ${task.file}:${task.line}`, `- ${task.message}`, ''].join('\n')),
24
+ ].join('\n');
25
+ export default async function migrateRichTextEditorLinkEditor(tree, schema) {
26
+ console.log('\n🔎 Scanning for rich text editor usage affected by the opt-in link editor...');
27
+ const scope = createMigrationScope(tree, schema);
28
+ console.log(` Scope: ${scope.describe()}`);
29
+ const tasks = [];
30
+ let hasLinkEditorProvider = false;
31
+ scope.visit(tree, (filePath) => {
32
+ if (!/\.(ts|html)$/.test(filePath) || filePath.endsWith('.d.ts'))
33
+ return;
34
+ const content = tree.read(filePath, 'utf-8');
35
+ if (!content)
36
+ return;
37
+ const result = scanRichTextEditorLinkEditorInFile(filePath, content);
38
+ tasks.push(...result.usages);
39
+ hasLinkEditorProvider ||= result.hasLinkEditorProvider;
40
+ });
41
+ if (hasLinkEditorProvider) {
42
+ console.log(' ✓ Found a provideRichTextEditorLinkEditor call — the popover is already opted back in.');
43
+ }
44
+ else if (tasks.length > 0) {
45
+ tree.write(RICH_TEXT_EDITOR_LINK_EDITOR_REPORT_PATH, renderReport(tasks));
46
+ }
47
+ if (!schema.skipFormat) {
48
+ await formatFiles(tree);
49
+ }
50
+ if (!hasLinkEditorProvider && tasks.length > 0) {
51
+ console.log(`\n⚠️ ${tasks.length} site(s) use the rich text editor without the link editor — see ${RICH_TEXT_EDITOR_LINK_EDITOR_REPORT_PATH}.`);
52
+ }
53
+ else {
54
+ console.log('\n✅ Nothing to do.');
55
+ }
56
+ }
57
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The rich text editor no longer mounts the link editor popover itself — it is an opt-in
3
+ * `provideRichTextEditorLinkEditor()`, and without it the `'link'` tool falls back to
4
+ * `window.prompt`. Whether an app wants the popover back is its own call, so this migration only
5
+ * finds the affected sites and reports them; it rewrites nothing.
6
+ */
7
+ const USAGE_MARKERS = [
8
+ 'et-rich-text-editor',
9
+ 'RICH_TEXT_EDITOR_IMPORTS',
10
+ 'RichTextEditorComponent',
11
+ 'etRichTextEditor',
12
+ ];
13
+ const OPT_IN_MARKER = 'provideRichTextEditorLinkEditor';
14
+ export const scanRichTextEditorLinkEditorInFile = (filePath, content) => {
15
+ const usages = [];
16
+ const marker = USAGE_MARKERS.find((m) => content.includes(m));
17
+ if (marker) {
18
+ const line = content.slice(0, content.indexOf(marker)).split('\n').length;
19
+ usages.push({
20
+ id: `rich-text-editor-link-editor--${filePath.replace(/[^a-zA-Z0-9]+/g, '-')}`,
21
+ file: filePath,
22
+ line,
23
+ message: `Uses the rich text editor (\`${marker}\`). Its link tool opens \`window.prompt\` now unless the link editor popover is provided.`,
24
+ });
25
+ }
26
+ return { usages, hasLinkEditorProvider: content.includes(OPT_IN_MARKER) };
27
+ };
28
+ //# sourceMappingURL=rich-text-editor-link-editor.js.map
@@ -0,0 +1,26 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "$id": "migrate-rich-text-editor-link-editor",
4
+ "title": "Find rich text editor usage affected by the opt-in link editor popover",
5
+ "type": "object",
6
+ "properties": {
7
+ "projects": {
8
+ "type": "array",
9
+ "items": { "type": "string" },
10
+ "description": "Nx projects to scan. Defaults to every project in the workspace.",
11
+ "alias": "project"
12
+ },
13
+ "include": {
14
+ "type": "array",
15
+ "items": { "type": "string" },
16
+ "description": "Path prefixes to scan, relative to the workspace root (e.g. 'apps/shop'). Unioned with `projects`.",
17
+ "alias": "includePath"
18
+ },
19
+ "skipFormat": {
20
+ "type": "boolean",
21
+ "description": "Skip formatting files after migration",
22
+ "default": false
23
+ }
24
+ },
25
+ "required": []
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethlete/components",
3
- "version": "1.0.0-next.32",
3
+ "version": "1.0.0-next.33",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -20,8 +20,14 @@
20
20
  "rxjs": "7.8.2"
21
21
  },
22
22
  "peerDependenciesMeta": {
23
+ "@analogjs/vitest-angular": {
24
+ "optional": true
25
+ },
23
26
  "@nx/devkit": {
24
27
  "optional": true
28
+ },
29
+ "date-fns": {
30
+ "optional": true
25
31
  }
26
32
  },
27
33
  "generators": "./generators/generators.json",