@sourceloop/search-client 1.1.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.
- package/.editorconfig +16 -0
- package/.prettierignore +4 -0
- package/CHANGELOG.md +26 -0
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/angular.json +53 -0
- package/package.json +61 -0
- package/projects/search-lib/.prettierignore +2 -0
- package/projects/search-lib/.prettierrc +7 -0
- package/projects/search-lib/karma.conf.js +41 -0
- package/projects/search-lib/ng-package.json +7 -0
- package/projects/search-lib/package.json +25 -0
- package/projects/search-lib/src/lib/lib-configuration.ts +62 -0
- package/projects/search-lib/src/lib/search/search.component.html +183 -0
- package/projects/search-lib/src/lib/search/search.component.scss +301 -0
- package/projects/search-lib/src/lib/search/search.component.ts +313 -0
- package/projects/search-lib/src/lib/search-lib.module.ts +12 -0
- package/projects/search-lib/src/lib/types.ts +59 -0
- package/projects/search-lib/src/public-api.ts +8 -0
- package/projects/search-lib/src/test.ts +34 -0
- package/projects/search-lib/tsconfig.lib.json +20 -0
- package/projects/search-lib/tsconfig.lib.prod.json +11 -0
- package/projects/search-lib/tsconfig.spec.json +17 -0
- package/tsconfig.json +36 -0
- package/tslint.json +163 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
ElementRef,
|
|
4
|
+
EventEmitter,
|
|
5
|
+
Inject,
|
|
6
|
+
Input,
|
|
7
|
+
OnDestroy,
|
|
8
|
+
OnInit,
|
|
9
|
+
Output,
|
|
10
|
+
PLATFORM_ID,
|
|
11
|
+
ViewChild,
|
|
12
|
+
} from '@angular/core';
|
|
13
|
+
import {Configuration} from '../lib-configuration';
|
|
14
|
+
import {Subject} from 'rxjs';
|
|
15
|
+
import {debounceTime, tap} from 'rxjs/operators';
|
|
16
|
+
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
|
|
17
|
+
import {
|
|
18
|
+
ISearchService,
|
|
19
|
+
IModel,
|
|
20
|
+
ISearchQuery,
|
|
21
|
+
SEARCH_SERVICE_TOKEN,
|
|
22
|
+
DEBOUNCE_TIME,
|
|
23
|
+
DEFAULT_LIMIT,
|
|
24
|
+
DEFAULT_LIMIT_TYPE,
|
|
25
|
+
DEFAULT_OFFSET,
|
|
26
|
+
DEFAULT_SAVE_IN_RECENTS,
|
|
27
|
+
DEFAULT_ORDER,
|
|
28
|
+
IReturnType,
|
|
29
|
+
RecentSearchEvent,
|
|
30
|
+
TypeEvent,
|
|
31
|
+
ItemClickedEvent,
|
|
32
|
+
} from '../types';
|
|
33
|
+
import {isPlatformBrowser} from '@angular/common';
|
|
34
|
+
|
|
35
|
+
@Component({
|
|
36
|
+
selector: 'sourceloop-search',
|
|
37
|
+
templateUrl: './search.component.html',
|
|
38
|
+
styleUrls: ['./search.component.scss'],
|
|
39
|
+
providers: [
|
|
40
|
+
{
|
|
41
|
+
provide: NG_VALUE_ACCESSOR,
|
|
42
|
+
useExisting: SearchComponent,
|
|
43
|
+
multi: true,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
})
|
|
47
|
+
export class SearchComponent<T extends IReturnType>
|
|
48
|
+
implements OnInit, OnDestroy, ControlValueAccessor
|
|
49
|
+
{
|
|
50
|
+
searchBoxInput = '';
|
|
51
|
+
suggestionsDisplay = false;
|
|
52
|
+
categoryDisplay = false;
|
|
53
|
+
suggestions: T[] = [];
|
|
54
|
+
relevantSuggestions: T[] = [];
|
|
55
|
+
recentSearches: ISearchQuery[] = [];
|
|
56
|
+
category: IModel | 'All' = 'All';
|
|
57
|
+
observableForSearchRequest = new Subject<{input: string; event: Event}>();
|
|
58
|
+
@Input() config!: Configuration<T>;
|
|
59
|
+
// emitted when user clicks one of the suggested results (including recent search sugestions)
|
|
60
|
+
@Output() clicked = new EventEmitter<ItemClickedEvent<T>>();
|
|
61
|
+
@Output() searched = new EventEmitter<RecentSearchEvent>();
|
|
62
|
+
/* emitted when user makes search request (including recent search requests & requests made on change in category from dropdown)
|
|
63
|
+
In case of recent search Array of recent Search request result is emitted */
|
|
64
|
+
|
|
65
|
+
onChange!: (value: string | undefined) => void;
|
|
66
|
+
onTouched!: () => void;
|
|
67
|
+
disabled = false;
|
|
68
|
+
|
|
69
|
+
@ViewChild('searchInput') public searchInputElement!: ElementRef;
|
|
70
|
+
|
|
71
|
+
constructor(
|
|
72
|
+
@Inject(SEARCH_SERVICE_TOKEN)
|
|
73
|
+
private readonly searchService: ISearchService<T>,
|
|
74
|
+
// tslint:disable-next-line:ban-types
|
|
75
|
+
@Inject(PLATFORM_ID) private readonly platformId: Object,
|
|
76
|
+
) {}
|
|
77
|
+
|
|
78
|
+
ngOnInit(): void {
|
|
79
|
+
this.observableForSearchRequest
|
|
80
|
+
.pipe(
|
|
81
|
+
tap(v => (this.suggestions = [])),
|
|
82
|
+
debounceTime(DEBOUNCE_TIME),
|
|
83
|
+
)
|
|
84
|
+
.subscribe((value: TypeEvent) => {
|
|
85
|
+
this.searched.emit({
|
|
86
|
+
event: value.event,
|
|
87
|
+
keyword: value.input,
|
|
88
|
+
category: this.category,
|
|
89
|
+
});
|
|
90
|
+
this.getSuggestions(value);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ControlValueAccessor Implementation
|
|
95
|
+
writeValue(value: string): void {
|
|
96
|
+
this.searchBoxInput = value;
|
|
97
|
+
}
|
|
98
|
+
// When the value in the UI is changed, this method will invoke a callback function
|
|
99
|
+
registerOnChange(fn: (value: string | undefined) => void): void {
|
|
100
|
+
this.onChange = fn;
|
|
101
|
+
}
|
|
102
|
+
registerOnTouched(fn: () => void): void {
|
|
103
|
+
this.onTouched = fn;
|
|
104
|
+
}
|
|
105
|
+
setDisabledState?(isDisabled: boolean): void {
|
|
106
|
+
this.disabled = isDisabled;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
getSuggestions(eventValue: TypeEvent) {
|
|
110
|
+
const order = this.config.order ?? DEFAULT_ORDER;
|
|
111
|
+
let orderString = '';
|
|
112
|
+
order.forEach(preference => (orderString = `${orderString}${preference} `));
|
|
113
|
+
|
|
114
|
+
let saveInRecents = this.config.saveInRecents ?? DEFAULT_SAVE_IN_RECENTS;
|
|
115
|
+
if (this.config.saveInRecents && this.config.saveInRecentsOnlyOnEnter) {
|
|
116
|
+
if (
|
|
117
|
+
(eventValue.event instanceof KeyboardEvent &&
|
|
118
|
+
eventValue.event.key === 'Enter') ||
|
|
119
|
+
(eventValue.event instanceof Event &&
|
|
120
|
+
eventValue.event.type === 'change')
|
|
121
|
+
) {
|
|
122
|
+
saveInRecents = true; // save in recents only on enter or change in category
|
|
123
|
+
} else {
|
|
124
|
+
// do not save in recent search on typing
|
|
125
|
+
saveInRecents = false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/* need to put default value here and not in contructor
|
|
129
|
+
because sonar was giving code smell with definite assertion as all these parameters are optional */
|
|
130
|
+
const requestParameters: ISearchQuery = {
|
|
131
|
+
match: eventValue.input,
|
|
132
|
+
sources: this._categoryToSourceName(this.category),
|
|
133
|
+
limit: this.config.limit ?? DEFAULT_LIMIT,
|
|
134
|
+
limitByType: this.config.limitByType ?? DEFAULT_LIMIT_TYPE,
|
|
135
|
+
order: orderString,
|
|
136
|
+
offset: this.config.offset ?? DEFAULT_OFFSET,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
this.searchService
|
|
140
|
+
.searchApiRequest(requestParameters, saveInRecents)
|
|
141
|
+
.subscribe(
|
|
142
|
+
(value: T[]) => {
|
|
143
|
+
this.suggestions = value;
|
|
144
|
+
},
|
|
145
|
+
(_error: Error) => {
|
|
146
|
+
this.suggestions = [];
|
|
147
|
+
},
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
getRecentSearches() {
|
|
151
|
+
if (
|
|
152
|
+
!this.config.hideRecentSearch &&
|
|
153
|
+
this.searchService.recentSearchApiRequest
|
|
154
|
+
) {
|
|
155
|
+
this.searchService.recentSearchApiRequest().subscribe(
|
|
156
|
+
(value: ISearchQuery[]) => {
|
|
157
|
+
this.recentSearches = value;
|
|
158
|
+
},
|
|
159
|
+
(_error: Error) => {
|
|
160
|
+
this.recentSearches = [];
|
|
161
|
+
},
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// event can be KeyBoardEvent or Event of type 'change' fired on change in value of drop down for category
|
|
167
|
+
hitSearchApi(event: Event) {
|
|
168
|
+
// this will happen only in case user searches something and then erases it, we need to update recent search
|
|
169
|
+
if (!this.searchBoxInput) {
|
|
170
|
+
this.suggestions = [];
|
|
171
|
+
this.getRecentSearches();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// no debounce time needed in case of searchOnlyOnEnter
|
|
176
|
+
if (this.config.searchOnlyOnEnter) {
|
|
177
|
+
if (
|
|
178
|
+
(event instanceof KeyboardEvent && event.key === 'Enter') ||
|
|
179
|
+
(event instanceof Event && event.type === 'change')
|
|
180
|
+
) {
|
|
181
|
+
this.getSuggestions({input: this.searchBoxInput, event});
|
|
182
|
+
}
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// no debounce time needed in case of change in category
|
|
187
|
+
if (event instanceof KeyboardEvent === false && event.type === 'change') {
|
|
188
|
+
this.getSuggestions({input: this.searchBoxInput, event});
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.observableForSearchRequest.next({
|
|
193
|
+
input: this.searchBoxInput,
|
|
194
|
+
event,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
populateValue(suggestion: T, event: MouseEvent) {
|
|
199
|
+
const value = suggestion[
|
|
200
|
+
this.config.displayPropertyName
|
|
201
|
+
] as unknown as string; // converted to string to assign value to searchBoxInput
|
|
202
|
+
this.searchBoxInput = value;
|
|
203
|
+
this.suggestionsDisplay = false;
|
|
204
|
+
// ngModelChange doesn't detect change in value when populated from outside, hence calling manually
|
|
205
|
+
this.onChange(this.searchBoxInput);
|
|
206
|
+
// need to do this to show more search options for selected suggestion - just in case user reopens search input
|
|
207
|
+
this.getSuggestions({input: this.searchBoxInput, event});
|
|
208
|
+
this.clicked.emit({item: suggestion, event});
|
|
209
|
+
}
|
|
210
|
+
populateValueRecentSearch(recentSearch: ISearchQuery, event: MouseEvent) {
|
|
211
|
+
event.stopPropagation();
|
|
212
|
+
event.preventDefault();
|
|
213
|
+
const value = recentSearch['match'];
|
|
214
|
+
this.searchBoxInput = value;
|
|
215
|
+
this.suggestionsDisplay = false;
|
|
216
|
+
this.onChange(this.searchBoxInput);
|
|
217
|
+
// need to do this to show more search options for selected suggestion - just in case user reopens search input
|
|
218
|
+
this.getSuggestions({input: this.searchBoxInput, event});
|
|
219
|
+
this.focusInput();
|
|
220
|
+
this.showSuggestions();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
fetchModelImageUrlFromSuggestion(suggestion: T) {
|
|
224
|
+
const modelName = suggestion[
|
|
225
|
+
'source' as unknown as keyof T
|
|
226
|
+
] as unknown as string;
|
|
227
|
+
let url: string | undefined;
|
|
228
|
+
this.config.models.forEach((model, i) => {
|
|
229
|
+
if (model.name === modelName && model.imageUrl) {
|
|
230
|
+
url = model.imageUrl;
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
return url;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// also returns true if there are any suggestions related to the model
|
|
237
|
+
getSuggestionsFromModelName(modelName: string) {
|
|
238
|
+
this.relevantSuggestions = [];
|
|
239
|
+
this.suggestions.forEach(suggestion => {
|
|
240
|
+
const sourceModelName = suggestion[
|
|
241
|
+
'source' as keyof T
|
|
242
|
+
] as unknown as string;
|
|
243
|
+
if (sourceModelName === modelName) {
|
|
244
|
+
this.relevantSuggestions.push(suggestion);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
if (this.relevantSuggestions.length) {
|
|
248
|
+
return true;
|
|
249
|
+
} else {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
boldString(str: T[keyof T] | string, substr: string) {
|
|
255
|
+
const strRegExp = new RegExp(`(${substr})`, 'gi');
|
|
256
|
+
const stringToMakeBold: string = str as unknown as string;
|
|
257
|
+
return stringToMakeBold.replace(strRegExp, `<b>$1</b>`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
hideSuggestions() {
|
|
261
|
+
this.suggestionsDisplay = false;
|
|
262
|
+
this.onTouched();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
showSuggestions() {
|
|
266
|
+
this.suggestionsDisplay = true;
|
|
267
|
+
this.getRecentSearches();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
focusInput() {
|
|
271
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
272
|
+
this.searchInputElement.nativeElement.focus();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
setCategory(category: 'All' | IModel, event: MouseEvent) {
|
|
277
|
+
this.category = category;
|
|
278
|
+
this.categoryDisplay = false;
|
|
279
|
+
if (this.searchBoxInput) {
|
|
280
|
+
this.hitSearchApi(event);
|
|
281
|
+
this.focusInput();
|
|
282
|
+
this.showSuggestions();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
showCategory() {
|
|
287
|
+
this.categoryDisplay = !this.categoryDisplay;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
hideCategory() {
|
|
291
|
+
this.categoryDisplay = false;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
resetInput() {
|
|
295
|
+
this.searchBoxInput = '';
|
|
296
|
+
this.suggestionsDisplay = true;
|
|
297
|
+
this.focusInput();
|
|
298
|
+
// ngModelChange doesn't detect change in value when populated from outside, hence calling manually
|
|
299
|
+
this.onChange(this.searchBoxInput);
|
|
300
|
+
this.getRecentSearches();
|
|
301
|
+
}
|
|
302
|
+
ngOnDestroy() {
|
|
303
|
+
this.observableForSearchRequest.unsubscribe();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
_categoryToSourceName(category: 'All' | IModel) {
|
|
307
|
+
if (category === 'All') {
|
|
308
|
+
return [];
|
|
309
|
+
} else {
|
|
310
|
+
return [category.name];
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {NgModule} from '@angular/core';
|
|
2
|
+
import {SearchComponent} from './search/search.component';
|
|
3
|
+
import {CommonModule} from '@angular/common';
|
|
4
|
+
import {FormsModule} from '@angular/forms';
|
|
5
|
+
import {HttpClientModule} from '@angular/common/http';
|
|
6
|
+
|
|
7
|
+
@NgModule({
|
|
8
|
+
declarations: [SearchComponent],
|
|
9
|
+
imports: [CommonModule, FormsModule, HttpClientModule],
|
|
10
|
+
exports: [SearchComponent],
|
|
11
|
+
})
|
|
12
|
+
export class SearchLibModule {}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {InjectionToken} from '@angular/core';
|
|
2
|
+
import {Observable} from 'rxjs';
|
|
3
|
+
|
|
4
|
+
export interface ISearchQuery {
|
|
5
|
+
match: string;
|
|
6
|
+
limit: number | null;
|
|
7
|
+
order: string | null;
|
|
8
|
+
limitByType: boolean | null;
|
|
9
|
+
offset: number | null;
|
|
10
|
+
sources: string[] | null;
|
|
11
|
+
}
|
|
12
|
+
export interface IModel {
|
|
13
|
+
name: string;
|
|
14
|
+
displayName: string;
|
|
15
|
+
imageUrl?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface IReturnType {
|
|
18
|
+
rank: number;
|
|
19
|
+
source: string;
|
|
20
|
+
}
|
|
21
|
+
export interface IDefaultReturnType extends IReturnType {
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ISearchService<T extends IReturnType> {
|
|
27
|
+
searchApiRequest(
|
|
28
|
+
requestParameters: ISearchQuery,
|
|
29
|
+
saveInRecents: boolean,
|
|
30
|
+
): Observable<T[]>;
|
|
31
|
+
recentSearchApiRequest?(): Observable<ISearchQuery[]>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// cant use T extends IReturnType here
|
|
35
|
+
export const SEARCH_SERVICE_TOKEN: InjectionToken<ISearchService<IReturnType>> =
|
|
36
|
+
new InjectionToken<ISearchService<IReturnType>>('Search_Service_Token');
|
|
37
|
+
|
|
38
|
+
export type RecentSearchEvent = {
|
|
39
|
+
event: KeyboardEvent | Event;
|
|
40
|
+
keyword: string;
|
|
41
|
+
category: 'All' | IModel;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type ItemClickedEvent<T> = {
|
|
45
|
+
event: MouseEvent;
|
|
46
|
+
item: T;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type TypeEvent = {
|
|
50
|
+
event: Event;
|
|
51
|
+
input: string;
|
|
52
|
+
};
|
|
53
|
+
// IRequestParameters default values
|
|
54
|
+
export const DEFAULT_LIMIT = 20;
|
|
55
|
+
export const DEFAULT_LIMIT_TYPE = false;
|
|
56
|
+
export const DEFAULT_ORDER = [];
|
|
57
|
+
export const DEBOUNCE_TIME = 1000;
|
|
58
|
+
export const DEFAULT_OFFSET = 0;
|
|
59
|
+
export const DEFAULT_SAVE_IN_RECENTS = true;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
|
2
|
+
import 'zone.js/dist/zone';
|
|
3
|
+
import 'zone.js/dist/long-stack-trace-zone';
|
|
4
|
+
import 'zone.js/dist/proxy';
|
|
5
|
+
import 'zone.js/dist/sync-test';
|
|
6
|
+
import 'zone.js/dist/jasmine-patch';
|
|
7
|
+
import 'zone.js/dist/async-test';
|
|
8
|
+
import 'zone.js/dist/fake-async-test';
|
|
9
|
+
import {getTestBed} from '@angular/core/testing';
|
|
10
|
+
import {
|
|
11
|
+
BrowserDynamicTestingModule,
|
|
12
|
+
platformBrowserDynamicTesting,
|
|
13
|
+
} from '@angular/platform-browser-dynamic/testing'; // NOSONAR
|
|
14
|
+
|
|
15
|
+
declare const require: {
|
|
16
|
+
context(
|
|
17
|
+
path: string,
|
|
18
|
+
deep?: boolean,
|
|
19
|
+
filter?: RegExp,
|
|
20
|
+
): {
|
|
21
|
+
keys(): string[];
|
|
22
|
+
<T>(id: string): T;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// First, initialize the Angular testing environment.
|
|
27
|
+
getTestBed().initTestEnvironment(
|
|
28
|
+
BrowserDynamicTestingModule,
|
|
29
|
+
platformBrowserDynamicTesting(),
|
|
30
|
+
);
|
|
31
|
+
// Then we find all the tests.
|
|
32
|
+
const context = require.context('./', true, /\.spec\.ts$/);
|
|
33
|
+
// And load the modules.
|
|
34
|
+
context.keys().forEach(context);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
+
{
|
|
3
|
+
"extends": "../../tsconfig.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"outDir": "../../out-tsc/lib",
|
|
6
|
+
"target": "es2015",
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"inlineSources": true,
|
|
10
|
+
"types": [],
|
|
11
|
+
"lib": [
|
|
12
|
+
"dom",
|
|
13
|
+
"es2018"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"exclude": [
|
|
17
|
+
"src/test.ts",
|
|
18
|
+
"**/*.spec.ts"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
+
{
|
|
3
|
+
"extends": "./tsconfig.lib.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"declarationMap": false
|
|
6
|
+
},
|
|
7
|
+
"angularCompilerOptions": {
|
|
8
|
+
"compilationMode": "partial",
|
|
9
|
+
"enableIvy": false
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
+
{
|
|
3
|
+
"extends": "../../tsconfig.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"outDir": "../../out-tsc/spec",
|
|
6
|
+
"types": [
|
|
7
|
+
"jasmine"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src/test.ts"
|
|
12
|
+
],
|
|
13
|
+
"include": [
|
|
14
|
+
"**/*.spec.ts",
|
|
15
|
+
"**/*.d.ts"
|
|
16
|
+
]
|
|
17
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
+
{
|
|
3
|
+
"compileOnSave": false,
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"baseUrl": "./",
|
|
6
|
+
"outDir": "./dist/out-tsc",
|
|
7
|
+
"forceConsistentCasingInFileNames": true,
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noImplicitReturns": true,
|
|
10
|
+
"noFallthroughCasesInSwitch": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"declaration": false,
|
|
13
|
+
"downlevelIteration": true,
|
|
14
|
+
"paths": {
|
|
15
|
+
"search-lib": [
|
|
16
|
+
"dist/search-lib/search-lib",
|
|
17
|
+
"dist/search-lib"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"experimentalDecorators": true,
|
|
21
|
+
"moduleResolution": "node",
|
|
22
|
+
"importHelpers": true,
|
|
23
|
+
"target": "es2017",
|
|
24
|
+
"module": "es2020",
|
|
25
|
+
"lib": [
|
|
26
|
+
"es2018",
|
|
27
|
+
"dom"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"angularCompilerOptions": {
|
|
31
|
+
"enableI18nLegacyMessageIdFormat": false,
|
|
32
|
+
"strictInjectionParameters": true,
|
|
33
|
+
"strictInputAccessModifiers": true,
|
|
34
|
+
"strictTemplates": true
|
|
35
|
+
}
|
|
36
|
+
}
|
package/tslint.json
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "tslint:recommended",
|
|
3
|
+
"rules": {
|
|
4
|
+
"align": {
|
|
5
|
+
"options": [
|
|
6
|
+
"parameters",
|
|
7
|
+
"statements"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
"array-type": false,
|
|
11
|
+
"arrow-parens": false,
|
|
12
|
+
"arrow-return-shorthand": true,
|
|
13
|
+
"deprecation": {
|
|
14
|
+
"severity": "warning"
|
|
15
|
+
},
|
|
16
|
+
"component-class-suffix": true,
|
|
17
|
+
"contextual-lifecycle": true,
|
|
18
|
+
"curly": true,
|
|
19
|
+
"directive-class-suffix": true,
|
|
20
|
+
"directive-selector": [
|
|
21
|
+
true,
|
|
22
|
+
"attribute",
|
|
23
|
+
"camelCase"
|
|
24
|
+
],
|
|
25
|
+
"no-string-literal": false,
|
|
26
|
+
"component-selector": [
|
|
27
|
+
true,
|
|
28
|
+
"element",
|
|
29
|
+
"kebab-case"
|
|
30
|
+
],
|
|
31
|
+
"eofline": true,
|
|
32
|
+
"import-blacklist": [
|
|
33
|
+
true,
|
|
34
|
+
"rxjs/Rx"
|
|
35
|
+
],
|
|
36
|
+
"import-spacing": true,
|
|
37
|
+
"indent": {
|
|
38
|
+
"options": [
|
|
39
|
+
"spaces"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"interface-name": false,
|
|
43
|
+
"max-classes-per-file": false,
|
|
44
|
+
"max-line-length": [
|
|
45
|
+
true,
|
|
46
|
+
140
|
|
47
|
+
],
|
|
48
|
+
"member-access": false,
|
|
49
|
+
"member-ordering": [
|
|
50
|
+
true,
|
|
51
|
+
{
|
|
52
|
+
"order": [
|
|
53
|
+
"static-field",
|
|
54
|
+
"instance-field",
|
|
55
|
+
"static-method",
|
|
56
|
+
"instance-method"
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"no-consecutive-blank-lines": false,
|
|
61
|
+
"no-any": false,
|
|
62
|
+
"no-console": [
|
|
63
|
+
true,
|
|
64
|
+
"debug",
|
|
65
|
+
"info",
|
|
66
|
+
"time",
|
|
67
|
+
"timeEnd",
|
|
68
|
+
"trace"
|
|
69
|
+
],
|
|
70
|
+
"no-empty": false,
|
|
71
|
+
"no-inferrable-types": [
|
|
72
|
+
true,
|
|
73
|
+
"ignore-params"
|
|
74
|
+
],
|
|
75
|
+
"no-non-null-assertion": true,
|
|
76
|
+
"no-redundant-jsdoc": true,
|
|
77
|
+
"no-switch-case-fall-through": true,
|
|
78
|
+
"no-var-requires": false,
|
|
79
|
+
"object-literal-key-quotes": [
|
|
80
|
+
true,
|
|
81
|
+
"as-needed"
|
|
82
|
+
],
|
|
83
|
+
"object-literal-sort-keys": false,
|
|
84
|
+
"ordered-imports": false,
|
|
85
|
+
"quotemark": [
|
|
86
|
+
true,
|
|
87
|
+
"single",
|
|
88
|
+
"avoid-escape"
|
|
89
|
+
],
|
|
90
|
+
"trailing-comma": false,
|
|
91
|
+
"no-conflicting-lifecycle": true,
|
|
92
|
+
"no-host-metadata-property": true,
|
|
93
|
+
"no-input-rename": true,
|
|
94
|
+
"no-inputs-metadata-property": true,
|
|
95
|
+
"no-output-native": true,
|
|
96
|
+
"no-output-on-prefix": false,
|
|
97
|
+
"no-output-rename": true,
|
|
98
|
+
"semicolon": {
|
|
99
|
+
"options": [
|
|
100
|
+
"always"
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
"space-before-function-paren": {
|
|
104
|
+
"options": {
|
|
105
|
+
"anonymous": "never",
|
|
106
|
+
"asyncArrow": "always",
|
|
107
|
+
"constructor": "never",
|
|
108
|
+
"method": "never",
|
|
109
|
+
"named": "never"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"no-outputs-metadata-property": true,
|
|
113
|
+
"template-banana-in-box": true,
|
|
114
|
+
"template-no-negated-async": true,
|
|
115
|
+
"typedef-whitespace": {
|
|
116
|
+
"options": [
|
|
117
|
+
{
|
|
118
|
+
"call-signature": "nospace",
|
|
119
|
+
"index-signature": "nospace",
|
|
120
|
+
"parameter": "nospace",
|
|
121
|
+
"property-declaration": "nospace",
|
|
122
|
+
"variable-declaration": "nospace"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"call-signature": "onespace",
|
|
126
|
+
"index-signature": "onespace",
|
|
127
|
+
"parameter": "onespace",
|
|
128
|
+
"property-declaration": "onespace",
|
|
129
|
+
"variable-declaration": "onespace"
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
"use-lifecycle-interface": false,
|
|
134
|
+
"use-pipe-transform-interface": true,
|
|
135
|
+
"one-variable-per-declaration": false,
|
|
136
|
+
"variable-name": {
|
|
137
|
+
"options": [
|
|
138
|
+
"ban-keywords",
|
|
139
|
+
"check-format",
|
|
140
|
+
"allow-pascal-case",
|
|
141
|
+
"allow-leading-underscore"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
"whitespace": {
|
|
145
|
+
"options": [
|
|
146
|
+
"check-branch",
|
|
147
|
+
"check-decl",
|
|
148
|
+
"check-operator",
|
|
149
|
+
"check-separator",
|
|
150
|
+
"check-type",
|
|
151
|
+
"check-typecast"
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"rulesDirectory": [
|
|
156
|
+
"codelyzer"
|
|
157
|
+
],
|
|
158
|
+
"linterOptions":{
|
|
159
|
+
"exclude":[
|
|
160
|
+
"**/theme/tools/**"
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
}
|