@koobiq/components 20.0.0 → 20.2.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/accordion/_accordion-theme.scss +1 -1
- package/accordion/accordion-tokens.scss +1 -0
- package/accordion/{accordion-trigger.component.scss → accordion-trigger.scss} +4 -18
- package/accordion/{accordion.component.scss → accordion.scss} +12 -5
- package/accordion/index.d.ts +215 -119
- package/actions-panel/index.d.ts +1 -0
- package/alert/_alert-theme.scss +14 -4
- package/alert/alert-tokens.scss +4 -4
- package/alert/alert.component.scss +24 -13
- package/alert/index.d.ts +63 -29
- package/app-switcher/app-switcher-dropdown-app.scss +2 -0
- package/autocomplete/autocomplete.scss +2 -1
- package/autocomplete/index.d.ts +35 -29
- package/badge/index.d.ts +2 -3
- package/breadcrumbs/breadcrumbs.scss +4 -0
- package/breadcrumbs/index.d.ts +2 -1
- package/button/button-group.scss +42 -2
- package/button-toggle/button-toggle.scss +23 -0
- package/button-toggle/index.d.ts +3 -1
- package/checkbox/checkbox.scss +5 -4
- package/clamped-text/index.d.ts +4 -2
- package/core/index.d.ts +515 -21
- package/core/styles/_core.scss +2 -0
- package/core/styles/common/_animation.scss +35 -24
- package/core/styles/common/_connected-overlay.scss +36 -0
- package/core/styles/common/_select.scss +7 -2
- package/core/styles/theming/_components-theming.scss +1 -1
- package/core/styles/theming/_scrollbar-theme.scss +4 -0
- package/datepicker/_datepicker-theme.scss +1 -1
- package/datepicker/datepicker-toggle.scss +3 -3
- package/dl/index.d.ts +1 -0
- package/dropdown/dropdown-item.scss +16 -0
- package/dropdown/dropdown-tokens.scss +2 -1
- package/dropdown/dropdown.scss +11 -2
- package/dropdown/index.d.ts +73 -6
- package/fesm2022/koobiq-components-accordion.mjs +406 -303
- package/fesm2022/koobiq-components-accordion.mjs.map +1 -1
- package/fesm2022/koobiq-components-actions-panel.mjs +15 -6
- package/fesm2022/koobiq-components-actions-panel.mjs.map +1 -1
- package/fesm2022/koobiq-components-alert.mjs +88 -48
- package/fesm2022/koobiq-components-alert.mjs.map +1 -1
- package/fesm2022/koobiq-components-app-switcher.mjs +7 -7
- package/fesm2022/koobiq-components-app-switcher.mjs.map +1 -1
- package/fesm2022/koobiq-components-autocomplete.mjs +37 -23
- package/fesm2022/koobiq-components-autocomplete.mjs.map +1 -1
- package/fesm2022/koobiq-components-badge.mjs +5 -4
- package/fesm2022/koobiq-components-badge.mjs.map +1 -1
- package/fesm2022/koobiq-components-breadcrumbs.mjs +6 -4
- package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
- package/fesm2022/koobiq-components-button-toggle.mjs +9 -6
- package/fesm2022/koobiq-components-button-toggle.mjs.map +1 -1
- package/fesm2022/koobiq-components-button.mjs +4 -4
- package/fesm2022/koobiq-components-button.mjs.map +1 -1
- package/fesm2022/koobiq-components-checkbox.mjs +2 -2
- package/fesm2022/koobiq-components-checkbox.mjs.map +1 -1
- package/fesm2022/koobiq-components-clamped-text.mjs +9 -0
- package/fesm2022/koobiq-components-clamped-text.mjs.map +1 -1
- package/fesm2022/koobiq-components-code-block.mjs +5 -1
- package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
- package/fesm2022/koobiq-components-core.mjs +544 -113
- package/fesm2022/koobiq-components-core.mjs.map +1 -1
- package/fesm2022/koobiq-components-datepicker.mjs +13 -10
- package/fesm2022/koobiq-components-datepicker.mjs.map +1 -1
- package/fesm2022/koobiq-components-dl.mjs +3 -2
- package/fesm2022/koobiq-components-dl.mjs.map +1 -1
- package/fesm2022/koobiq-components-dropdown.mjs +105 -31
- package/fesm2022/koobiq-components-dropdown.mjs.map +1 -1
- package/fesm2022/koobiq-components-file-upload.mjs +33 -22
- package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
- package/fesm2022/koobiq-components-filter-bar.mjs +1169 -782
- package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
- package/fesm2022/koobiq-components-flag.mjs +66 -0
- package/fesm2022/koobiq-components-flag.mjs.map +1 -0
- package/fesm2022/koobiq-components-form-field.mjs +6 -6
- package/fesm2022/koobiq-components-form-field.mjs.map +1 -1
- package/fesm2022/koobiq-components-icon.mjs +16 -7
- package/fesm2022/koobiq-components-icon.mjs.map +1 -1
- package/fesm2022/koobiq-components-inline-edit.mjs +30 -7
- package/fesm2022/koobiq-components-inline-edit.mjs.map +1 -1
- package/fesm2022/koobiq-components-list.mjs +39 -20
- package/fesm2022/koobiq-components-list.mjs.map +1 -1
- package/fesm2022/koobiq-components-loader-overlay.mjs +2 -2
- package/fesm2022/koobiq-components-loader-overlay.mjs.map +1 -1
- package/fesm2022/koobiq-components-modal.mjs +9 -5
- package/fesm2022/koobiq-components-modal.mjs.map +1 -1
- package/fesm2022/koobiq-components-navbar.mjs +123 -27
- package/fesm2022/koobiq-components-navbar.mjs.map +1 -1
- package/fesm2022/koobiq-components-notification-center.mjs +193 -19
- package/fesm2022/koobiq-components-notification-center.mjs.map +1 -1
- package/fesm2022/koobiq-components-overflow-items.mjs +12 -4
- package/fesm2022/koobiq-components-overflow-items.mjs.map +1 -1
- package/fesm2022/koobiq-components-popover.mjs +9 -4
- package/fesm2022/koobiq-components-popover.mjs.map +1 -1
- package/fesm2022/koobiq-components-progress-bar.mjs +2 -2
- package/fesm2022/koobiq-components-progress-bar.mjs.map +1 -1
- package/fesm2022/koobiq-components-progress-spinner.mjs +2 -2
- package/fesm2022/koobiq-components-progress-spinner.mjs.map +1 -1
- package/fesm2022/koobiq-components-radio.mjs +3 -7
- package/fesm2022/koobiq-components-radio.mjs.map +1 -1
- package/fesm2022/koobiq-components-search-expandable.mjs +43 -8
- package/fesm2022/koobiq-components-search-expandable.mjs.map +1 -1
- package/fesm2022/koobiq-components-select.mjs +72 -59
- package/fesm2022/koobiq-components-select.mjs.map +1 -1
- package/fesm2022/koobiq-components-sidebar.mjs +4 -0
- package/fesm2022/koobiq-components-sidebar.mjs.map +1 -1
- package/fesm2022/koobiq-components-sidepanel.mjs +3 -3
- package/fesm2022/koobiq-components-sidepanel.mjs.map +1 -1
- package/fesm2022/koobiq-components-skeleton.mjs +2 -2
- package/fesm2022/koobiq-components-skeleton.mjs.map +1 -1
- package/fesm2022/koobiq-components-split-button.mjs +5 -12
- package/fesm2022/koobiq-components-split-button.mjs.map +1 -1
- package/fesm2022/koobiq-components-splitter.mjs +6 -2
- package/fesm2022/koobiq-components-splitter.mjs.map +1 -1
- package/fesm2022/koobiq-components-table.mjs +8 -6
- package/fesm2022/koobiq-components-table.mjs.map +1 -1
- package/fesm2022/koobiq-components-tabs.mjs +42 -18
- package/fesm2022/koobiq-components-tabs.mjs.map +1 -1
- package/fesm2022/koobiq-components-tags.mjs +8 -1
- package/fesm2022/koobiq-components-tags.mjs.map +1 -1
- package/fesm2022/koobiq-components-textarea.mjs +7 -14
- package/fesm2022/koobiq-components-textarea.mjs.map +1 -1
- package/fesm2022/koobiq-components-time-range.mjs +4 -4
- package/fesm2022/koobiq-components-time-range.mjs.map +1 -1
- package/fesm2022/koobiq-components-timepicker.mjs +3 -4
- package/fesm2022/koobiq-components-timepicker.mjs.map +1 -1
- package/fesm2022/koobiq-components-timezone.mjs +9 -5
- package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
- package/fesm2022/koobiq-components-title.mjs +132 -14
- package/fesm2022/koobiq-components-title.mjs.map +1 -1
- package/fesm2022/koobiq-components-toast.mjs +1 -1
- package/fesm2022/koobiq-components-toast.mjs.map +1 -1
- package/fesm2022/koobiq-components-toggle.mjs +2 -2
- package/fesm2022/koobiq-components-toggle.mjs.map +1 -1
- package/fesm2022/koobiq-components-tooltip.mjs +168 -8
- package/fesm2022/koobiq-components-tooltip.mjs.map +1 -1
- package/fesm2022/koobiq-components-tree-select.mjs +79 -38
- package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
- package/fesm2022/koobiq-components-tree.mjs +67 -41
- package/fesm2022/koobiq-components-tree.mjs.map +1 -1
- package/fesm2022/koobiq-components-username.mjs +16 -3
- package/fesm2022/koobiq-components-username.mjs.map +1 -1
- package/file-upload/file-upload-tokens.scss +1 -0
- package/file-upload/index.d.ts +10 -7
- package/filter-bar/_filter-bar-theme.scss +82 -0
- package/filter-bar/filter-bar-tokens.scss +9 -0
- package/filter-bar/filter-bar.scss +10 -4
- package/filter-bar/filter-refresher.scss +1 -1
- package/filter-bar/filters.scss +25 -20
- package/filter-bar/index.d.ts +764 -336
- package/filter-bar/pipes/base-pipe.scss +12 -44
- package/filter-bar/pipes/pipe-date.scss +20 -14
- package/filter-bar/pipes/pipe-input.scss +10 -0
- package/filter-bar/pipes/pipe-multi-tree-select.scss +5 -3
- package/filter-bar/pipes/pipe-multiselect.scss +5 -3
- package/filter-bar/pipes/pipe-readonly.scss +4 -13
- package/filter-bar/pipes/pipe-select.scss +3 -1
- package/filter-bar/pipes/pipe-tree-select.scss +3 -1
- package/flag/flag.scss +53 -0
- package/flag/index.d.ts +44 -0
- package/icon/icon-button.scss +3 -1
- package/icon/icon-item-tokens.scss +1 -1
- package/icon/index.d.ts +15 -2
- package/inline-edit/index.d.ts +5 -0
- package/inline-edit/inline-edit.scss +7 -7
- package/link/link-tokens.scss +2 -2
- package/list/index.d.ts +11 -2
- package/loader-overlay/loader-overlay-tokens.scss +1 -1
- package/modal/_modal-animation.scss +6 -6
- package/modal/_modal-theme.scss +5 -0
- package/modal/index.d.ts +3 -1
- package/modal/modal.scss +15 -0
- package/navbar/_navbar-item_vertical.scss +7 -5
- package/navbar/index.d.ts +39 -4
- package/navbar/navbar-brand.scss +17 -7
- package/navbar/navbar-item.scss +9 -0
- package/notification-center/_notification-center-theme.scss +2 -1
- package/notification-center/index.d.ts +89 -3
- package/notification-center/notification-center.scss +42 -4
- package/notification-center/notification-item.scss +3 -2
- package/overflow-items/index.d.ts +1 -0
- package/package.json +7 -3
- package/prebuilt-themes/dark-theme.css +1 -1
- package/prebuilt-themes/light-theme.css +1 -1
- package/prebuilt-themes/theme.css +1 -1
- package/progress-bar/progress-bar.scss +4 -0
- package/progress-spinner/progress-spinner.scss +5 -1
- package/radio/index.d.ts +1 -5
- package/radio/radio.scss +18 -4
- package/schematics/collection.json +15 -0
- package/schematics/migrations/alert-signals/README.md +64 -0
- package/schematics/migrations/alert-signals/data.js +70 -0
- package/schematics/migrations/alert-signals/index.js +350 -0
- package/schematics/migrations/alert-signals/schema.json +20 -0
- package/schematics/migrations/autocomplete-panel-width-auto/README.md +68 -0
- package/schematics/migrations/autocomplete-panel-width-auto/index.js +70 -0
- package/schematics/migrations/autocomplete-panel-width-auto/schema.json +15 -0
- package/schematics/migrations/filter-bar-signals/README.md +66 -0
- package/schematics/migrations/filter-bar-signals/data.js +72 -0
- package/schematics/migrations/filter-bar-signals/index.js +316 -0
- package/schematics/migrations/filter-bar-signals/schema.json +20 -0
- package/schematics/migrations.json +15 -0
- package/schematics/ng-add/index.js +1 -1
- package/schematics/utils/angular-parsing.js +11 -2
- package/search-expandable/index.d.ts +3 -0
- package/select/index.d.ts +59 -24
- package/sidebar/index.d.ts +1 -0
- package/skeleton/skeleton.scss +4 -0
- package/split-button/_split-button-theme.scss +2 -2
- package/splitter/_splitter-theme.scss +2 -2
- package/splitter/index.d.ts +1 -0
- package/table/_table-theme.scss +4 -0
- package/table/index.d.ts +3 -2
- package/tabs/_tabs-common.scss +60 -31
- package/tabs/_tabs-theme.scss +12 -0
- package/tabs/index.d.ts +4 -2
- package/tabs/tab-header.scss +15 -0
- package/tabs/tab-nav-bar.scss +4 -0
- package/tabs/tabs-tokens.scss +2 -1
- package/textarea/index.d.ts +0 -1
- package/time-range/time-range.scss +0 -8
- package/timepicker/timepicker.scss +2 -2
- package/timezone/index.d.ts +2 -3
- package/title/index.d.ts +92 -2
- package/tooltip/index.d.ts +124 -7
- package/tree/_tree-theme.scss +2 -7
- package/tree/index.d.ts +19 -4
- package/tree/toggle.scss +5 -0
- package/tree/tree-option.scss +0 -4
- package/tree-select/_tree-select-theme.scss +1 -1
- package/tree-select/index.d.ts +53 -22
- package/username/index.d.ts +20 -2
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var node_path = require('node:path');
|
|
6
|
+
var process = require('node:process');
|
|
7
|
+
var ts = require('typescript');
|
|
8
|
+
var utils_angularParsing = require('../../utils/angular-parsing.js');
|
|
9
|
+
var utils_packageConfig = require('../../utils/package-config.js');
|
|
10
|
+
var utils_typescript = require('../../utils/typescript.js');
|
|
11
|
+
require('path');
|
|
12
|
+
require('../../utils/ast.js');
|
|
13
|
+
require('@angular-devkit/schematics');
|
|
14
|
+
require('@schematics/angular/utility');
|
|
15
|
+
require('../../utils/messages.js');
|
|
16
|
+
|
|
17
|
+
function _interopNamespaceDefault(e) {
|
|
18
|
+
var n = Object.create(null);
|
|
19
|
+
if (e) {
|
|
20
|
+
Object.keys(e).forEach(function (k) {
|
|
21
|
+
if (k !== 'default') {
|
|
22
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
23
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return e[k]; }
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
n.default = e;
|
|
31
|
+
return Object.freeze(n);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
var process__namespace = /*#__PURE__*/_interopNamespaceDefault(process);
|
|
35
|
+
|
|
36
|
+
const migrationData = {
|
|
37
|
+
elementName: 'kbq-autocomplete',
|
|
38
|
+
attrs: {
|
|
39
|
+
key: {
|
|
40
|
+
from: 'panelWidth',
|
|
41
|
+
to: 'panelWidth'
|
|
42
|
+
},
|
|
43
|
+
value: {
|
|
44
|
+
replacements: [{ from: 'auto', to: 'fit-content' }]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
function migrate(options) {
|
|
49
|
+
return async (tree, context) => {
|
|
50
|
+
const { project } = options;
|
|
51
|
+
const { tsPaths, templatePaths, projectDefinition } = await utils_packageConfig.getParsingInfo(project, tree);
|
|
52
|
+
const program = ts.createProgram(Array.from(tsPaths, (item) => node_path.resolve(projectDefinition.root, `.${item}`)), {
|
|
53
|
+
baseUrl: projectDefinition.root,
|
|
54
|
+
rootDir: projectDefinition.root,
|
|
55
|
+
_enableTemplateTypeChecker: true, // Required for the template type checker to work.
|
|
56
|
+
compileNonExportedClasses: true, // We want to migrate non-exported classes too.
|
|
57
|
+
// Avoid checking libraries to speed up the migration.
|
|
58
|
+
skipLibCheck: true,
|
|
59
|
+
skipDefaultLibCheck: true
|
|
60
|
+
});
|
|
61
|
+
// Update external html
|
|
62
|
+
await utils_angularParsing.migrateTemplate(tree, Array.from(templatePaths), context, migrationData);
|
|
63
|
+
// Update inline html
|
|
64
|
+
await utils_angularParsing.migrateTs(tree, program.getSourceFiles().filter((sourceFile) => utils_typescript.canMigrateFile(sourceFile, program)), process__namespace.cwd(), context, migrationData);
|
|
65
|
+
context.logger.warn('Warning! Run linter in updated files since line breaks or indents may be broken.');
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
exports.default = migrate;
|
|
70
|
+
exports.migrationData = migrationData;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"$id": "koobiq-components-autocomplete-panel-width-auto",
|
|
4
|
+
"title": "koobiq-components autocomplete-panel-width-auto schematic",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"project": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Name of the project",
|
|
10
|
+
"$default": {
|
|
11
|
+
"$source": "projectName"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# filter-bar-signals
|
|
2
|
+
|
|
3
|
+
Migration schematic invoked automatically by `ng update @koobiq/components@20`.
|
|
4
|
+
Migrates consumers of `KbqFilterBar` to its signal-based public API.
|
|
5
|
+
|
|
6
|
+
## Why
|
|
7
|
+
|
|
8
|
+
`KbqFilterBar` moved several members from accessors/getters to signals. Reading
|
|
9
|
+
them programmatically now requires a call, and assigning `filter` now goes
|
|
10
|
+
through `.set(...)`. Template _bindings_ (`[filter]`, `[(filter)]`,
|
|
11
|
+
`[pipeTemplates]`) keep working — only reads break.
|
|
12
|
+
|
|
13
|
+
| Member | Before | After |
|
|
14
|
+
| --------------------------------------------------------------------------- | -------- | ----------------- |
|
|
15
|
+
| `filter` | accessor | `ModelSignal` |
|
|
16
|
+
| `pipeTemplates` | accessor | `InputSignal` |
|
|
17
|
+
| `isChanged` / `isDisabled` / `isReadOnly` / `isSaved` / `isSavedAndChanged` | getter | `Signal<boolean>` |
|
|
18
|
+
|
|
19
|
+
## What it does
|
|
20
|
+
|
|
21
|
+
The schematic walks every `.ts` and `.html` file in the project (skipping
|
|
22
|
+
`node_modules` and `dist`) and, for files that reference the filter bar:
|
|
23
|
+
|
|
24
|
+
- **TypeScript reads/writes.** For a receiver whose static type is annotated
|
|
25
|
+
`KbqFilterBar` / `KbqFilterBarHost` (method/function params, class fields —
|
|
26
|
+
including `@ViewChild(KbqFilterBar) x: KbqFilterBar` and constructor
|
|
27
|
+
parameter-properties — and typed locals), a read of a signal member becomes a
|
|
28
|
+
call and a `filter` write becomes `.set(...)`:
|
|
29
|
+
- `filterBar.filter` → `filterBar.filter()` (incl. optional chain `filterBar.filter?.name` → `filterBar.filter()?.name`)
|
|
30
|
+
- `filterBar.filter = next` → `filterBar.filter.set(next)`
|
|
31
|
+
- `this.filterBar.isChanged` → `this.filterBar.isChanged()`
|
|
32
|
+
- **Template reference reads.** For a `#ref` bound to `<kbq-filter-bar>`, reads
|
|
33
|
+
of signal members through that ref are rewritten in the same template
|
|
34
|
+
(external `.html` and inline `template:` strings): `ref.isChanged` →
|
|
35
|
+
`ref.isChanged()`.
|
|
36
|
+
- **Rename.** `KbqFilterBarRefresher` → `KbqFilterRefresher` (the old name is
|
|
37
|
+
still re-exported as an alias, so this is optional cleanup).
|
|
38
|
+
|
|
39
|
+
All rewrites are idempotent — running twice does not double the call.
|
|
40
|
+
|
|
41
|
+
## What it does _not_ do (warn-only)
|
|
42
|
+
|
|
43
|
+
Some changes require code restructuring and are surfaced as warnings without
|
|
44
|
+
auto-fixing:
|
|
45
|
+
|
|
46
|
+
| Pattern | Manual migration |
|
|
47
|
+
| -------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
48
|
+
| `.changes` (KbqFilterBar) | Deprecated no-op; read `filterBar.filter()` inside an `effect(...)`, or listen to `(filterChange)` |
|
|
49
|
+
| `.preparePopover()` (KbqFilters) | Removed; use `openSaveAsNewFilterPopover()` / `openChangeFilterNamePopover()` |
|
|
50
|
+
| `viewChild(KbqFilterBar)` query | Returns the instance, so reads are a double call: `this.filterBar().filter()` — verify manually |
|
|
51
|
+
| `KBQ_FILTER_BAR_PIPES` | Now typed `Map<KbqPipeType, Type<KbqBasePipe>>`; wrap direct providers in `new Map([...])` |
|
|
52
|
+
|
|
53
|
+
## Running it manually
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
ng generate @koobiq/components:filter-bar-signals --project my-app
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Pass `--fix=false` to see what would change without writing files.
|
|
60
|
+
|
|
61
|
+
## Limitations
|
|
62
|
+
|
|
63
|
+
Receivers are matched by explicit `KbqFilterBar` type annotation only (no
|
|
64
|
+
cross-package type inference), so aliased/inferred receivers
|
|
65
|
+
(`const fb = this.filterBar; fb.filter`) are left untouched and covered by the
|
|
66
|
+
warnings above. After running, **always inspect the diff** before committing.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Data for the `filter-bar-signals` migration.
|
|
5
|
+
*
|
|
6
|
+
* `KbqFilterBar` moved several members from accessors/getters to signals. Reading them programmatically
|
|
7
|
+
* (in `.ts` code or via a template reference variable) now requires a call:
|
|
8
|
+
*
|
|
9
|
+
* - `filterBar.filter` → `filterBar.filter()` (write `= v` → `.set(v)`)
|
|
10
|
+
* - `filterBar.pipeTemplates` → `filterBar.pipeTemplates()`
|
|
11
|
+
* - `filterBar.isChanged` → `filterBar.isChanged()` (also isDisabled/isReadOnly/isSaved/isSavedAndChanged)
|
|
12
|
+
*
|
|
13
|
+
* Template *bindings* (`[filter]`, `[(filter)]`, `[pipeTemplates]`) keep working — only reads break.
|
|
14
|
+
*/
|
|
15
|
+
/** Members of `KbqFilterBar` that became signals; a read of any of them must become a call. */
|
|
16
|
+
const SIGNAL_MEMBERS = [
|
|
17
|
+
'filter',
|
|
18
|
+
'pipeTemplates',
|
|
19
|
+
'isChanged',
|
|
20
|
+
'isDisabled',
|
|
21
|
+
'isReadOnly',
|
|
22
|
+
'isSaved',
|
|
23
|
+
'isSavedAndChanged'
|
|
24
|
+
];
|
|
25
|
+
/** Signal members that are writable (`model()`); `x.filter = v` migrates to `x.filter.set(v)`. */
|
|
26
|
+
const WRITABLE_MEMBERS = new Set(['filter']);
|
|
27
|
+
/** TypeScript type annotations that mark a receiver as a filter bar. */
|
|
28
|
+
const FILTER_BAR_TYPE = 'KbqFilterBar';
|
|
29
|
+
const FILTER_BAR_HOST_TYPE = 'KbqFilterBarHost';
|
|
30
|
+
/** Element selector whose template reference variables (`#ref`) point at a filter bar. */
|
|
31
|
+
const FILTER_BAR_ELEMENT = 'kbq-filter-bar';
|
|
32
|
+
/**
|
|
33
|
+
* Safe, idempotent identifier renames applied to `.ts` files. The `\b…\b` boundaries make each rule
|
|
34
|
+
* idempotent. `KbqFilterBarRefresher` is still re-exported as an alias of `KbqFilterRefresher`, so this
|
|
35
|
+
* is optional cleanup that can never break a consumer build.
|
|
36
|
+
*/
|
|
37
|
+
const tsRenameReplacements = [{ from: '\\bKbqFilterBarRefresher\\b', to: 'KbqFilterRefresher' }];
|
|
38
|
+
/**
|
|
39
|
+
* Patterns that can't be auto-fixed reliably — surfaced with file locations (in both `fix` and dry-run
|
|
40
|
+
* mode). Only evaluated for files that reference the filter bar, so the broad `.changes` pattern stays scoped.
|
|
41
|
+
*/
|
|
42
|
+
const warnPatterns = [
|
|
43
|
+
{
|
|
44
|
+
pattern: '\\.changes\\b',
|
|
45
|
+
message: 'KbqFilterBar.changes is deprecated and no longer emits. Reactivity is driven by the `filter` ' +
|
|
46
|
+
'signal now — read it with `filterBar.filter()` inside an `effect(...)`, or listen to the ' +
|
|
47
|
+
'`(filterChange)` output. (Best-effort match — ignore if this `.changes` is unrelated.)'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
pattern: '\\.preparePopover\\(',
|
|
51
|
+
message: 'KbqFilters.preparePopover() was removed. Use openSaveAsNewFilterPopover() / ' +
|
|
52
|
+
'openChangeFilterNamePopover() instead.'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
pattern: '(?:viewChild|ViewChild)[^\\n;]*\\bKbqFilterBar\\b',
|
|
56
|
+
message: 'A KbqFilterBar view/signal query returns the component instance, whose filter is now a signal — ' +
|
|
57
|
+
'reading it is a double call, e.g. `this.filterBar().filter()`. Verify query reads manually.'
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
pattern: '\\bKBQ_FILTER_BAR_PIPES\\b',
|
|
61
|
+
message: 'KBQ_FILTER_BAR_PIPES is now typed as Map<KbqPipeType, Type<KbqBasePipe>> (was an array of tuples). ' +
|
|
62
|
+
'If you provide it directly, wrap the entries in `new Map([...])`.'
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
exports.FILTER_BAR_ELEMENT = FILTER_BAR_ELEMENT;
|
|
67
|
+
exports.FILTER_BAR_HOST_TYPE = FILTER_BAR_HOST_TYPE;
|
|
68
|
+
exports.FILTER_BAR_TYPE = FILTER_BAR_TYPE;
|
|
69
|
+
exports.SIGNAL_MEMBERS = SIGNAL_MEMBERS;
|
|
70
|
+
exports.WRITABLE_MEMBERS = WRITABLE_MEMBERS;
|
|
71
|
+
exports.tsRenameReplacements = tsRenameReplacements;
|
|
72
|
+
exports.warnPatterns = warnPatterns;
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var ts = require('typescript');
|
|
6
|
+
var utils_ast = require('../../utils/ast.js');
|
|
7
|
+
var utils_messages = require('../../utils/messages.js');
|
|
8
|
+
var utils_packageConfig = require('../../utils/package-config.js');
|
|
9
|
+
var utils_typescript = require('../../utils/typescript.js');
|
|
10
|
+
var migrations_filterBarSignals_data = require('./data.js');
|
|
11
|
+
require('@angular-devkit/schematics');
|
|
12
|
+
require('@schematics/angular/utility');
|
|
13
|
+
|
|
14
|
+
const TS_EXT = '.ts';
|
|
15
|
+
const HTML_EXT = '.html';
|
|
16
|
+
function escapeRegExp(value) {
|
|
17
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
18
|
+
}
|
|
19
|
+
/** Applies text-span edits to `content`, right-to-left, so earlier edits don't shift later offsets. */
|
|
20
|
+
function applyEdits(content, edits) {
|
|
21
|
+
const sorted = [...edits].sort((a, b) => b.start - a.start || b.end - a.end);
|
|
22
|
+
let result = content;
|
|
23
|
+
for (const { start, end, text } of sorted) {
|
|
24
|
+
result = result.slice(0, start) + text + result.slice(end);
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
const isFunctionLike = (node) => ts.isFunctionDeclaration(node) ||
|
|
29
|
+
ts.isMethodDeclaration(node) ||
|
|
30
|
+
ts.isConstructorDeclaration(node) ||
|
|
31
|
+
ts.isArrowFunction(node) ||
|
|
32
|
+
ts.isFunctionExpression(node) ||
|
|
33
|
+
ts.isGetAccessorDeclaration(node) ||
|
|
34
|
+
ts.isSetAccessorDeclaration(node);
|
|
35
|
+
/** Walks up from `node` to the nearest ancestor matching `predicate`. */
|
|
36
|
+
function findAncestor(node, predicate) {
|
|
37
|
+
let current = node.parent;
|
|
38
|
+
while (current) {
|
|
39
|
+
if (predicate(current))
|
|
40
|
+
return current;
|
|
41
|
+
current = current.parent;
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
/** Whether a type annotation refers to the filter bar (`KbqFilterBar` / `KbqFilterBarHost`). */
|
|
46
|
+
function isFilterBarType(type) {
|
|
47
|
+
return (!!type &&
|
|
48
|
+
ts.isTypeReferenceNode(type) &&
|
|
49
|
+
ts.isIdentifier(type.typeName) &&
|
|
50
|
+
(type.typeName.text === migrations_filterBarSignals_data.FILTER_BAR_TYPE || type.typeName.text === migrations_filterBarSignals_data.FILTER_BAR_HOST_TYPE));
|
|
51
|
+
}
|
|
52
|
+
const FIELD_MODIFIERS = new Set([
|
|
53
|
+
ts.SyntaxKind.PrivateKeyword,
|
|
54
|
+
ts.SyntaxKind.PublicKeyword,
|
|
55
|
+
ts.SyntaxKind.ProtectedKeyword,
|
|
56
|
+
ts.SyntaxKind.ReadonlyKeyword
|
|
57
|
+
]);
|
|
58
|
+
/**
|
|
59
|
+
* Collects the receivers whose static type is a filter bar, by explicit annotation only (no cross-package
|
|
60
|
+
* type resolution): method/function params, class fields (incl. `@ViewChild(KbqFilterBar) x: KbqFilterBar`
|
|
61
|
+
* and constructor parameter-properties) and typed locals.
|
|
62
|
+
*/
|
|
63
|
+
function collectReceivers(sourceFile) {
|
|
64
|
+
const receivers = [];
|
|
65
|
+
const add = (text, scope) => receivers.push({ text, start: scope.getStart(sourceFile), end: scope.getEnd() });
|
|
66
|
+
const visit = (node) => {
|
|
67
|
+
if (ts.isParameter(node) && ts.isIdentifier(node.name) && isFilterBarType(node.type)) {
|
|
68
|
+
add(node.name.text, findAncestor(node, isFunctionLike) ?? sourceFile);
|
|
69
|
+
// A constructor parameter-property is also a class field, reachable as `this.<name>`.
|
|
70
|
+
if (node.modifiers?.some((modifier) => FIELD_MODIFIERS.has(modifier.kind))) {
|
|
71
|
+
const owner = findAncestor(node, ts.isClassDeclaration);
|
|
72
|
+
if (owner)
|
|
73
|
+
add(`this.${node.name.text}`, owner);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (ts.isPropertyDeclaration(node) && ts.isIdentifier(node.name) && isFilterBarType(node.type)) {
|
|
77
|
+
const owner = findAncestor(node, ts.isClassDeclaration);
|
|
78
|
+
if (owner)
|
|
79
|
+
add(`this.${node.name.text}`, owner);
|
|
80
|
+
}
|
|
81
|
+
else if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && isFilterBarType(node.type)) {
|
|
82
|
+
add(node.name.text, findAncestor(node, isFunctionLike) ?? sourceFile);
|
|
83
|
+
}
|
|
84
|
+
node.forEachChild(visit);
|
|
85
|
+
};
|
|
86
|
+
visit(sourceFile);
|
|
87
|
+
return receivers;
|
|
88
|
+
}
|
|
89
|
+
/** Classifies a matched property access and appends the resulting edit(s). */
|
|
90
|
+
function classifyAccess(node, sourceFile, edits) {
|
|
91
|
+
const parent = node.parent;
|
|
92
|
+
// Already migrated: `x.filter()` (call) or `x.filter.set(...)` — leave alone (idempotent).
|
|
93
|
+
if (ts.isCallExpression(parent) && parent.expression === node)
|
|
94
|
+
return;
|
|
95
|
+
if (ts.isPropertyAccessExpression(parent) && parent.expression === node && parent.name.text === 'set')
|
|
96
|
+
return;
|
|
97
|
+
// Write target: `x.filter = RHS` → `x.filter.set(RHS)` (writable members only).
|
|
98
|
+
if (ts.isBinaryExpression(parent) &&
|
|
99
|
+
parent.left === node &&
|
|
100
|
+
parent.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
101
|
+
if (migrations_filterBarSignals_data.WRITABLE_MEMBERS.has(node.name.text)) {
|
|
102
|
+
const rhs = parent.right;
|
|
103
|
+
// Replace ` = ` with `.set(` and close after the right-hand side; keeping the RHS span intact
|
|
104
|
+
// lets any nested read edits inside it still apply.
|
|
105
|
+
edits.push({ start: node.getEnd(), end: rhs.getStart(sourceFile), text: '.set(' });
|
|
106
|
+
edits.push({ start: rhs.getEnd(), end: rhs.getEnd(), text: ')' });
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
// Read (incl. optional chain `x?.filter`): append `()`.
|
|
111
|
+
edits.push({ start: node.getEnd(), end: node.getEnd(), text: '()' });
|
|
112
|
+
}
|
|
113
|
+
/** Collects edits for every read/write of a signal member on a known filter-bar receiver. */
|
|
114
|
+
function collectAccessEdits(sourceFile, receivers) {
|
|
115
|
+
const edits = [];
|
|
116
|
+
const visit = (node) => {
|
|
117
|
+
if (ts.isPropertyAccessExpression(node) &&
|
|
118
|
+
ts.isIdentifier(node.name) &&
|
|
119
|
+
migrations_filterBarSignals_data.SIGNAL_MEMBERS.includes(node.name.text)) {
|
|
120
|
+
const receiverText = node.expression.getText(sourceFile);
|
|
121
|
+
const start = node.getStart(sourceFile);
|
|
122
|
+
const end = node.getEnd();
|
|
123
|
+
const inScope = receivers.some((r) => r.text === receiverText && start >= r.start && end <= r.end);
|
|
124
|
+
if (inScope)
|
|
125
|
+
classifyAccess(node, sourceFile, edits);
|
|
126
|
+
}
|
|
127
|
+
node.forEachChild(visit);
|
|
128
|
+
};
|
|
129
|
+
visit(sourceFile);
|
|
130
|
+
return edits;
|
|
131
|
+
}
|
|
132
|
+
/** Pass A — rewrite programmatic reads/writes of filter-bar signal members in TypeScript code. */
|
|
133
|
+
function migrateTsExpressions(content, fileName) {
|
|
134
|
+
const sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
135
|
+
const receivers = collectReceivers(sourceFile);
|
|
136
|
+
if (receivers.length === 0)
|
|
137
|
+
return content;
|
|
138
|
+
const edits = collectAccessEdits(sourceFile, receivers);
|
|
139
|
+
return edits.length > 0 ? applyEdits(content, edits) : content;
|
|
140
|
+
}
|
|
141
|
+
/** Collects template reference variable names bound to a `<kbq-filter-bar>` element. */
|
|
142
|
+
class FilterBarRefCollector {
|
|
143
|
+
constructor() {
|
|
144
|
+
this.refs = new Set();
|
|
145
|
+
}
|
|
146
|
+
visitElement(element) {
|
|
147
|
+
if (element.name === migrations_filterBarSignals_data.FILTER_BAR_ELEMENT) {
|
|
148
|
+
for (const attr of element.attrs ?? []) {
|
|
149
|
+
if (typeof attr.name !== 'string')
|
|
150
|
+
continue;
|
|
151
|
+
if (attr.name.startsWith('#'))
|
|
152
|
+
this.refs.add(attr.name.slice(1));
|
|
153
|
+
else if (attr.name.startsWith('ref-'))
|
|
154
|
+
this.refs.add(attr.name.slice(4));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
this.visitChildren(element);
|
|
158
|
+
}
|
|
159
|
+
visitBlock(block) {
|
|
160
|
+
this.visitChildren(block);
|
|
161
|
+
}
|
|
162
|
+
visitChildren(node) {
|
|
163
|
+
for (const child of node.children ?? []) {
|
|
164
|
+
child.visit(this);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
visitAttribute() { }
|
|
168
|
+
visitText() { }
|
|
169
|
+
visitComment() { }
|
|
170
|
+
visitExpansion() { }
|
|
171
|
+
visitExpansionCase() { }
|
|
172
|
+
visitBlockParameter() { }
|
|
173
|
+
visitLetDeclaration() { }
|
|
174
|
+
}
|
|
175
|
+
/** Rewrites `ref.member` reads to `ref.member()` for the given refs, scoped to those exact identifiers. */
|
|
176
|
+
function rewriteRefReads(template, refs) {
|
|
177
|
+
const members = migrations_filterBarSignals_data.SIGNAL_MEMBERS.join('|');
|
|
178
|
+
let content = template;
|
|
179
|
+
let changed = false;
|
|
180
|
+
for (const ref of refs) {
|
|
181
|
+
// `\bref\.(member)\b(?!\s*\()` — skip anything already invoked, so the rewrite is idempotent.
|
|
182
|
+
const pattern = new RegExp(`\\b(${escapeRegExp(ref)})\\.(${members})\\b(?!\\s*\\()`, 'g');
|
|
183
|
+
const next = content.replace(pattern, '$1.$2()');
|
|
184
|
+
if (next !== content) {
|
|
185
|
+
content = next;
|
|
186
|
+
changed = true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return { content, changed };
|
|
190
|
+
}
|
|
191
|
+
/** Pass B (core) — parse a template, discover filter-bar refs, rewrite their signal reads. */
|
|
192
|
+
async function migrateTemplate(template) {
|
|
193
|
+
if (!template.includes(migrations_filterBarSignals_data.FILTER_BAR_ELEMENT))
|
|
194
|
+
return { content: template, changed: false };
|
|
195
|
+
const parsed = await utils_typescript.parseTemplate(template);
|
|
196
|
+
if (!parsed.tree)
|
|
197
|
+
return { content: template, changed: false };
|
|
198
|
+
const collector = new FilterBarRefCollector();
|
|
199
|
+
utils_ast.visitAll(collector, parsed.tree.rootNodes);
|
|
200
|
+
if (collector.refs.size === 0)
|
|
201
|
+
return { content: template, changed: false };
|
|
202
|
+
return rewriteRefReads(template, [...collector.refs]);
|
|
203
|
+
}
|
|
204
|
+
/** Interior `[start, end]` ranges of inline `@Component({ template: '…' })` string literals. */
|
|
205
|
+
function collectInlineTemplateRanges(sourceFile) {
|
|
206
|
+
const ranges = [];
|
|
207
|
+
utils_typescript.forEachClass(sourceFile, (node) => {
|
|
208
|
+
const decorator = ts
|
|
209
|
+
.getDecorators(node)
|
|
210
|
+
?.find((dec) => ts.isCallExpression(dec.expression) &&
|
|
211
|
+
ts.isIdentifier(dec.expression.expression) &&
|
|
212
|
+
dec.expression.expression.text === 'Component');
|
|
213
|
+
if (!decorator || !ts.isCallExpression(decorator.expression))
|
|
214
|
+
return;
|
|
215
|
+
const [arg] = decorator.expression.arguments;
|
|
216
|
+
if (!arg || !ts.isObjectLiteralExpression(arg))
|
|
217
|
+
return;
|
|
218
|
+
for (const prop of arg.properties) {
|
|
219
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
220
|
+
(ts.isIdentifier(prop.name) || ts.isStringLiteralLike(prop.name)) &&
|
|
221
|
+
prop.name.text === 'template' &&
|
|
222
|
+
ts.isStringLiteralLike(prop.initializer) &&
|
|
223
|
+
prop.initializer.text) {
|
|
224
|
+
// +1 / -1 to exclude the opening/closing quote characters.
|
|
225
|
+
ranges.push({ start: prop.initializer.getStart(sourceFile) + 1, end: prop.initializer.getEnd() - 1 });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
return ranges;
|
|
230
|
+
}
|
|
231
|
+
/** Pass B (inline) — rewrite filter-bar ref reads inside inline component templates. */
|
|
232
|
+
async function migrateInlineTemplates(content, fileName) {
|
|
233
|
+
const sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
234
|
+
const ranges = collectInlineTemplateRanges(sourceFile).sort((a, b) => b.start - a.start);
|
|
235
|
+
let result = content;
|
|
236
|
+
for (const { start, end } of ranges) {
|
|
237
|
+
const { content: rewritten, changed } = await migrateTemplate(result.slice(start, end));
|
|
238
|
+
if (changed) {
|
|
239
|
+
result = result.slice(0, start) + rewritten + result.slice(end);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
244
|
+
/** Pass C — safe identifier renames. */
|
|
245
|
+
function applyRenames(content) {
|
|
246
|
+
let result = content;
|
|
247
|
+
for (const { from, to } of migrations_filterBarSignals_data.tsRenameReplacements) {
|
|
248
|
+
result = result.replace(new RegExp(from, 'g'), to);
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
function logWarnings(context, filePath, content) {
|
|
253
|
+
for (const { pattern, message } of migrations_filterBarSignals_data.warnPatterns) {
|
|
254
|
+
if (new RegExp(pattern).test(content)) {
|
|
255
|
+
utils_messages.logMessage(context.logger, [`[filter-bar-signals] ${filePath}`, ` ${message}`]);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/** A `.ts` file is a filter-bar consumer if it names the type or imports the package. */
|
|
260
|
+
function referencesFilterBar(content) {
|
|
261
|
+
return /\bKbqFilterBar\b/.test(content) || content.includes('@koobiq/components/filter-bar');
|
|
262
|
+
}
|
|
263
|
+
function filterBarSignals(options) {
|
|
264
|
+
return async (tree, context) => {
|
|
265
|
+
const { project, fix } = options;
|
|
266
|
+
const projectDefinition = await utils_packageConfig.setupOptions(project, tree);
|
|
267
|
+
const root = projectDefinition?.root ?? '';
|
|
268
|
+
const rootDir = root ? tree.getDir(root) : tree.root;
|
|
269
|
+
const tsPaths = [];
|
|
270
|
+
const htmlPaths = [];
|
|
271
|
+
rootDir.visit((filePath) => {
|
|
272
|
+
if (filePath.includes('node_modules') || filePath.includes('/dist/'))
|
|
273
|
+
return;
|
|
274
|
+
if (filePath.endsWith(TS_EXT))
|
|
275
|
+
tsPaths.push(filePath);
|
|
276
|
+
else if (filePath.endsWith(HTML_EXT))
|
|
277
|
+
htmlPaths.push(filePath);
|
|
278
|
+
});
|
|
279
|
+
let touched = 0;
|
|
280
|
+
const commit = (filePath, original, updated) => {
|
|
281
|
+
if (updated === original)
|
|
282
|
+
return;
|
|
283
|
+
touched++;
|
|
284
|
+
if (fix) {
|
|
285
|
+
tree.overwrite(filePath, updated);
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
utils_messages.logMessage(context.logger, [`[filter-bar-signals] would update ${filePath} (run with --fix to apply)`]);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
for (const filePath of tsPaths) {
|
|
292
|
+
const original = tree.read(filePath)?.toString();
|
|
293
|
+
if (!original || !referencesFilterBar(original))
|
|
294
|
+
continue;
|
|
295
|
+
logWarnings(context, filePath, original);
|
|
296
|
+
let content = migrateTsExpressions(original, filePath);
|
|
297
|
+
content = await migrateInlineTemplates(content, filePath);
|
|
298
|
+
content = applyRenames(content);
|
|
299
|
+
commit(filePath, original, content);
|
|
300
|
+
}
|
|
301
|
+
for (const filePath of htmlPaths) {
|
|
302
|
+
const original = tree.read(filePath)?.toString();
|
|
303
|
+
if (!original)
|
|
304
|
+
continue;
|
|
305
|
+
const { content, changed } = await migrateTemplate(original);
|
|
306
|
+
if (changed)
|
|
307
|
+
commit(filePath, original, content);
|
|
308
|
+
}
|
|
309
|
+
utils_messages.logMessage(context.logger, [
|
|
310
|
+
`[filter-bar-signals] processed tree under "${root || '<workspace root>'}", ` +
|
|
311
|
+
`${fix ? 'updated' : 'would update'} ${touched} file(s).`
|
|
312
|
+
]);
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
exports.default = filterBarSignals;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"$id": "koobiq-components-filter-bar-signals",
|
|
4
|
+
"title": "Koobiq components filter-bar signals migration",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"project": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Name of the project to migrate. If omitted, the migration runs over the whole tree.",
|
|
10
|
+
"$default": {
|
|
11
|
+
"$source": "projectName"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"fix": {
|
|
15
|
+
"type": "boolean",
|
|
16
|
+
"default": true,
|
|
17
|
+
"description": "When true, applies all auto-fix replacements. When false, prints what would change without writing."
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
"version": "20.0.0-0",
|
|
6
6
|
"description": "Migrates code from deprecated APIs removed in @koobiq/components v20.0.0. Handles package moves (@koobiq/cdk/{a11y,keycodes,testing} → @koobiq/components/core, navbar-ic, risk-level, experimental form-field), TypeScript identifier renames, template selector renames (e.g. <kbq-filter-search> → <kbq-search-expandable>, <kbq-datepicker-toggle> → <kbq-datepicker-toggle-icon>), attribute renames (kbqFormFieldWithoutBorders → noBorders), tooltip modifier inputs, and emits warnings for structural changes that need manual migration (onSaveAsNew, file-upload customValidation/errors, app-switcher apps).",
|
|
7
7
|
"factory": "./migrations/v20-upgrade/index"
|
|
8
|
+
},
|
|
9
|
+
"filter-bar-signals": {
|
|
10
|
+
"version": "20.2.0-0",
|
|
11
|
+
"description": "Migrates KbqFilterBar consumers to the signal-based API. Rewrites programmatic reads of the now-signal members (filter, pipeTemplates, isChanged, isDisabled, isReadOnly, isSaved, isSavedAndChanged) to calls and `filter = v` writes to `filter.set(v)` on receivers typed KbqFilterBar, including reads via template reference variables on <kbq-filter-bar>. Renames KbqFilterBarRefresher → KbqFilterRefresher and warns on changes/preparePopover/view-query cases that need manual migration.",
|
|
12
|
+
"factory": "./migrations/filter-bar-signals/index"
|
|
13
|
+
},
|
|
14
|
+
"alert-signals": {
|
|
15
|
+
"version": "20.2.0-0",
|
|
16
|
+
"description": "Migrates KbqAlert consumers to its finished signal-based API. Rewrites value-safe programmatic reads of the now-signal members (compact, alertStyle) to calls on receivers typed KbqAlert, including reads via template reference variables on <kbq-alert> (external and inline templates). Warns — without auto-fixing — on alertColor (now a read-only InputSignal whose getter returns the raw color instead of the `kbq-alert_<color>` class), the content-query members that became protected (icon/iconItem/button/title/control/closeButton/isColored), narrowed alertColor/alertStyle inputs, the compact booleanAttribute behavior change, descendants:false content projection, view/content queries returning the instance, and KbqAlertModule no longer re-exporting A11yModule/PlatformModule.",
|
|
17
|
+
"factory": "./migrations/alert-signals/index"
|
|
18
|
+
},
|
|
19
|
+
"autocomplete-panel-width-auto": {
|
|
20
|
+
"version": "20.2.0-0",
|
|
21
|
+
"description": "Replaces `panelWidth=\"auto\"` with `panelWidth=\"fit-content\"` on `<kbq-autocomplete>`. `auto` used to be passed to CSS verbatim, so the panel shrank to fit its content; it now means \"match the host width\", matching `kbq-select` and `kbq-tree-select`. The change is silent — `auto` still type-checks and still renders — so unmigrated templates only lay out differently.",
|
|
22
|
+
"factory": "./migrations/autocomplete-panel-width-auto/index"
|
|
8
23
|
}
|
|
9
24
|
}
|
|
10
25
|
}
|
|
@@ -27,7 +27,7 @@ function ngAdd(options) {
|
|
|
27
27
|
}
|
|
28
28
|
// Installing dependencies
|
|
29
29
|
utils_packageConfig.addPackageToPackageJson(tree, '@angular/cdk', "^20.2.14");
|
|
30
|
-
utils_packageConfig.addPackageToPackageJson(tree, '@koobiq/angular-luxon-adapter', "^20.
|
|
30
|
+
utils_packageConfig.addPackageToPackageJson(tree, '@koobiq/angular-luxon-adapter', "^20.2.0");
|
|
31
31
|
utils_packageConfig.addPackageToPackageJson(tree, '@koobiq/date-formatter', "^3.5.1");
|
|
32
32
|
utils_packageConfig.addPackageToPackageJson(tree, '@koobiq/date-adapter', "^3.5.1");
|
|
33
33
|
utils_packageConfig.addPackageToPackageJson(tree, '@koobiq/icons', "^11.7.1");
|
|
@@ -122,6 +122,7 @@ async function transformTemplateAttributes(template, fileName, migrationData) {
|
|
|
122
122
|
if (parsed.tree !== undefined) {
|
|
123
123
|
const visitor = new utils_typescript.ElementCollector(migrationData, fileName);
|
|
124
124
|
utils_ast.visitAll(visitor, parsed.tree.rootNodes);
|
|
125
|
+
let didReplace = false;
|
|
125
126
|
for (const el of visitor.elementsToMigrate) {
|
|
126
127
|
const migrationAttr = el.attrs.find((attr) => utils_ast.getSimpleAttributeName(attr.name) === migrationData.attrs.key.from);
|
|
127
128
|
let updatedAttrValue;
|
|
@@ -132,7 +133,14 @@ async function transformTemplateAttributes(template, fileName, migrationData) {
|
|
|
132
133
|
updatedAttrValue = replacement.to;
|
|
133
134
|
}
|
|
134
135
|
else {
|
|
135
|
-
|
|
136
|
+
// A bound attribute (`[panelWidth]="..."`) whose value isn't a quoted string
|
|
137
|
+
// literal is a genuine runtime expression and can't be resolved statically. A
|
|
138
|
+
// plain attribute, or a bound attribute holding a quoted literal, has a known
|
|
139
|
+
// value at migration time — it's just one the replacement table doesn't cover.
|
|
140
|
+
const isDynamicExpression = migrationAttr.name.startsWith('[') && !/^\s*['"].*['"]\s*$/.test(migrationAttr.value);
|
|
141
|
+
console.warn(isDynamicExpression
|
|
142
|
+
? `Element is using a dynamic value. Check the code and change value on your own.${(fileName && ' File: ' + fileName) || ''}`
|
|
143
|
+
: `Element has value "${cleanAttrValue}" with no matching replacement. Check the code and change value on your own.${(fileName && ' File: ' + fileName) || ''}`);
|
|
136
144
|
continue;
|
|
137
145
|
}
|
|
138
146
|
updatedTemplate =
|
|
@@ -141,9 +149,10 @@ async function transformTemplateAttributes(template, fileName, migrationData) {
|
|
|
141
149
|
updatedTemplate.slice(migrationAttr.valueSpan.end.offset + 1 - offset, updatedTemplate.length);
|
|
142
150
|
offset += migrationAttr.name.length - migrationData.attrs.key.to.length;
|
|
143
151
|
offset += migrationAttr.value.length - updatedAttrValue.length;
|
|
152
|
+
didReplace = true;
|
|
144
153
|
}
|
|
145
154
|
}
|
|
146
|
-
return { fileContent: updatedTemplate, changed:
|
|
155
|
+
return { fileContent: updatedTemplate, changed: didReplace, errors: parsed.errors };
|
|
147
156
|
}
|
|
148
157
|
return { fileContent: updatedTemplate, changed: undefined, errors: parsed.errors };
|
|
149
158
|
}
|
|
@@ -35,6 +35,8 @@ declare class KbqSearchExpandable implements ControlValueAccessor, AfterViewInit
|
|
|
35
35
|
/** Current value in input. */
|
|
36
36
|
value: BehaviorSubject<string>;
|
|
37
37
|
protected lastFocusOrigin: 'touch' | 'mouse' | 'keyboard' | 'program' | null;
|
|
38
|
+
/** Suppress the automatic input focus once — set when the component auto-opens from a model value. */
|
|
39
|
+
private suppressInputFocus;
|
|
38
40
|
/** state of component. */
|
|
39
41
|
isOpened: boolean;
|
|
40
42
|
/** Emit event by enter or not. Default is false */
|
|
@@ -77,6 +79,7 @@ declare class KbqSearchExpandable implements ControlValueAccessor, AfterViewInit
|
|
|
77
79
|
/** Implemented as part of ControlValueAccessor. */
|
|
78
80
|
setDisabledState(isDisabled: boolean): void;
|
|
79
81
|
toggle(): void;
|
|
82
|
+
private setOpened;
|
|
80
83
|
private updateLocaleParams;
|
|
81
84
|
private initDefaultParams;
|
|
82
85
|
private emitValue;
|