Proyecto App Linux
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# @iptvnator/pipes
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test @iptvnator/pipes` to execute the unit tests.
|
||||
@@ -0,0 +1,34 @@
|
||||
import nx from '@nx/eslint-plugin';
|
||||
import baseConfig from '../../../eslint.config.mjs';
|
||||
|
||||
export default [
|
||||
...baseConfig,
|
||||
...nx.configs['flat/angular'],
|
||||
...nx.configs['flat/angular-template'],
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'attribute',
|
||||
prefix: 'lib',
|
||||
style: 'camelCase',
|
||||
},
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'element',
|
||||
prefix: 'lib',
|
||||
style: 'kebab-case',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.html'],
|
||||
// Override or add rules here
|
||||
rules: {},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,21 @@
|
||||
export default {
|
||||
displayName: '@iptvnator/pipes',
|
||||
preset: '../../../jest.preset.js',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
||||
coverageDirectory: '../../../coverage/libs/ui/pipes',
|
||||
transform: {
|
||||
'^.+\\.(ts|mjs|js|html)$': [
|
||||
'jest-preset-angular',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
},
|
||||
],
|
||||
},
|
||||
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
|
||||
snapshotSerializers: [
|
||||
'jest-preset-angular/build/serializers/no-ng-attributes',
|
||||
'jest-preset-angular/build/serializers/ng-snapshot',
|
||||
'jest-preset-angular/build/serializers/html-comment',
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@iptvnator/pipes",
|
||||
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/ui/pipes/src",
|
||||
"prefix": "lib",
|
||||
"projectType": "library",
|
||||
"tags": ["scope:shared", "domain:shared-ui", "type:util"],
|
||||
"targets": {
|
||||
"test": {
|
||||
"executor": "nx:run-commands",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"command": [
|
||||
"node",
|
||||
"./tools/testing/run-web-esm-lib-tests.mjs",
|
||||
"libs/ui/pipes/src"
|
||||
],
|
||||
"env": {
|
||||
"NODE_OPTIONS": "--experimental-vm-modules"
|
||||
},
|
||||
"forwardAllArgs": true
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './lib/filter.pipe';
|
||||
export * from './lib/date-format.util';
|
||||
export * from './lib/safe.pipe';
|
||||
export * from './lib/sort.pipe';
|
||||
@@ -0,0 +1,24 @@
|
||||
import { formatWithIntl, normalizeDateLocale } from './date-format.util';
|
||||
|
||||
describe('date-format.util', () => {
|
||||
it('normalizes app locale aliases to Angular/Intl locale ids', () => {
|
||||
expect(normalizeDateLocale('ary')).toBe('ar-MA');
|
||||
expect(normalizeDateLocale('by')).toBe('be');
|
||||
expect(normalizeDateLocale('zhtw')).toBe('zh-Hant');
|
||||
expect(normalizeDateLocale('de')).toBe('de');
|
||||
expect(normalizeDateLocale()).toBe('en');
|
||||
});
|
||||
|
||||
it('formats dates with cached Intl formatters', () => {
|
||||
expect(
|
||||
formatWithIntl('2026-04-05T12:30:00.000Z', {
|
||||
locale: 'de',
|
||||
timeZone: 'UTC',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
).toContain('12:30');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
const DEFAULT_DATE_LOCALE = 'en';
|
||||
|
||||
const DATE_LOCALE_ALIASES: Record<string, string> = {
|
||||
ary: 'ar-MA',
|
||||
by: 'be',
|
||||
zhtw: 'zh-Hant',
|
||||
};
|
||||
|
||||
const formatterCache = new Map<string, Intl.DateTimeFormat>();
|
||||
|
||||
export function normalizeDateLocale(locale?: string | null): string {
|
||||
const normalizedLocale = String(locale ?? '').trim();
|
||||
|
||||
if (!normalizedLocale) {
|
||||
return DEFAULT_DATE_LOCALE;
|
||||
}
|
||||
|
||||
return (
|
||||
DATE_LOCALE_ALIASES[normalizedLocale.toLowerCase()] ?? normalizedLocale
|
||||
);
|
||||
}
|
||||
|
||||
export function formatWithIntl(
|
||||
value: Date | number | string,
|
||||
options: Intl.DateTimeFormatOptions & {
|
||||
locale?: string | null;
|
||||
timeZone?: string;
|
||||
} = {}
|
||||
): string {
|
||||
const date =
|
||||
value instanceof Date
|
||||
? value
|
||||
: typeof value === 'number'
|
||||
? new Date(value)
|
||||
: new Date(value);
|
||||
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const { locale, ...formatOptions } = options;
|
||||
const resolvedLocale = normalizeDateLocale(locale);
|
||||
const cacheKey = JSON.stringify([resolvedLocale, formatOptions]);
|
||||
|
||||
let formatter = formatterCache.get(cacheKey);
|
||||
if (!formatter) {
|
||||
formatter = new Intl.DateTimeFormat(resolvedLocale, formatOptions);
|
||||
formatterCache.set(cacheKey, formatter);
|
||||
}
|
||||
|
||||
return formatter.format(date);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Injectable, Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'filterBy',
|
||||
standalone: true,
|
||||
})
|
||||
@Injectable()
|
||||
export class FilterPipe implements PipeTransform {
|
||||
transform(array: any[], filter: string, property: string): any {
|
||||
if (!array || !filter) {
|
||||
return array;
|
||||
}
|
||||
return array.filter((item) =>
|
||||
item[property].toLowerCase().includes(filter.toLowerCase())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
|
||||
@Pipe({ name: 'safe', standalone: true })
|
||||
export class SafePipe implements PipeTransform {
|
||||
constructor(private sanitizer: DomSanitizer) {}
|
||||
|
||||
transform(url: string) {
|
||||
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Injectable, Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'sortBy',
|
||||
standalone: true,
|
||||
})
|
||||
@Injectable()
|
||||
export class SortPipe implements PipeTransform {
|
||||
transform(array: any[], sortType: string): any {
|
||||
if (!array || !sortType) {
|
||||
return array;
|
||||
}
|
||||
return array.sort((a, b) => {
|
||||
if (sortType === 'date') {
|
||||
return parseInt(b.added) - parseInt(a.added);
|
||||
} else if (sortType === 'rating') {
|
||||
const ratingA = isNaN(parseFloat(a.rating)) ? 0 : parseFloat(a.rating);
|
||||
const ratingB = isNaN(parseFloat(b.rating)) ? 0 : parseFloat(b.rating);
|
||||
return ratingB - ratingA;
|
||||
} else if (sortType === 'alpha') {
|
||||
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
|
||||
|
||||
setupZoneTestEnv({
|
||||
errorOnUnknownElements: true,
|
||||
errorOnUnknownProperties: true,
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "preserve"
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"typeCheckHostBindings": true,
|
||||
"strictTemplates": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/test-setup.ts",
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts"
|
||||
],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"target": "es2016",
|
||||
"types": ["jest", "node"],
|
||||
"moduleResolution": "node10"
|
||||
},
|
||||
"files": ["src/test-setup.ts"],
|
||||
"include": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user