2
0
mirror of https://github.com/iconify/iconify.git synced 2024-11-09 23:00:56 +00:00

WIP: moving core to unbuild and vitest

This commit is contained in:
Vjacheslav Trushkin 2022-03-16 12:12:25 +02:00
parent 1618e49698
commit 5feccddcb3
23 changed files with 1290 additions and 249 deletions

View File

@ -1,2 +1 @@
lib
tests-compiled

View File

@ -4,12 +4,22 @@ module.exports = {
es6: true,
node: true,
},
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:prettier/recommended',
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parser: '@typescript-eslint/parser',
parserOptions: {
tsconfigRootDir: __dirname,
project: ['tsconfig.json', 'tests/tsconfig.json'],
extraFileExtensions: ['.cjs'],
},
plugins: ['@typescript-eslint'],
rules: {
'no-mixed-spaces-and-tabs': ['off'],

View File

@ -2,9 +2,7 @@
.DS_Store
*.map
node_modules
imports-test.mjs
npm-debug.log
yarn.lock
tsconfig.tsbuildinfo
lib
tests-compiled

View File

@ -2,12 +2,16 @@
.vscode
.DS_Store
*.map
.eslintignore
node_modules
imports-test.mjs
npm-debug.log
yarn.lock
tsconfig.tsbuildinfo
.eslintrc.cjs
tsconfig.json
jest.config.*
jest.shared.config.cjs
vitest.config.*
build.config.ts
src
spec
tests
tests-compiled

View File

@ -0,0 +1,11 @@
const { buildConfiguration } = require('./jest.shared.config.cjs');
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = buildConfiguration({
moduleFileExtensions: ['ts', 'cjs', 'js'],
globals: {
'ts-jest': {
useESM: false,
},
},
});

View File

@ -1,8 +0,0 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
verbose: true,
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/tests/**/*-test.ts'],
moduleFileExtensions: ['ts', 'cjs', 'js'],
};

View File

@ -0,0 +1,10 @@
import pkg from './jest.shared.config.cjs';
export default pkg.buildConfiguration({
moduleFileExtensions: ['ts', 'mjs', 'js'],
globals: {
'ts-jest': {
useESM: true,
},
},
})

View File

@ -0,0 +1,25 @@
/**
* Jest shared configuration: see https://jestjs.io/docs/ecmascript-modules.
*
* @param {import('ts-jest/dist/types').InitialOptionsTsJest} configuration
* @return {import('ts-jest/dist/types').InitialOptionsTsJest}
*/
function buildConfiguration(configuration) {
return Object.assign(
{},
{
verbose: true,
testEnvironment: 'node',
moduleDirectories: ['node_modules', 'src'],
extensionsToTreatAsEsm: ['.ts'],
transform: {
'^.+\\.ts$': 'ts-jest',
},
testMatch: ['**/tests/**/*-test.ts'],
},
configuration
);
}
exports.buildConfiguration = buildConfiguration;
module.exports = { buildConfiguration };

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
{
"name": "@iconify/core",
"type": "module",
"description": "Reusable files used by multiple Iconify packages",
"author": "Vjacheslav Trushkin <cyberalien@gmail.com> (https://iconify.design)",
"version": "1.2.4",
@ -12,13 +13,18 @@
"directory": "packages/core"
},
"scripts": {
"clean": "rimraf lib tests-compiled tsconfig.tsbuildinfo",
"lint": "eslint src/**/*.ts",
"clean": "rimraf lib tsconfig.tsbuildinfo",
"lint": "eslint --fix src/**/*.ts",
"prebuild": "npm run lint && npm run clean",
"build": "unbuild",
"test:jest": "jest --runInBand",
"test": "npm run test:jest"
"test:jest-cjs": "jest --clearCache && jest --runInBand --config=jest.config.cjs",
"test:jest-esm": "jest --clearCache && cross-env NODE_OPTIONS=--experimental-vm-modules npx jest --runInBand --config=jest.config.mjs",
"test": "npm run test:jest-cjs && npm run test:jest-esm",
"vitest:cjs": "vitest --config vitest.config.cjs",
"vitest:esm": "vitest --config vitest.config.mjs",
"vitest": "npm run vitest:cjs && npm run vitest:esm"
},
"sideEffects": false,
"exports": {
"./*": "./*",
"./lib/api/callbacks": {
@ -99,21 +105,25 @@
}
},
"dependencies": {
"@iconify/api-redundancy": "^1.0.2",
"@iconify/api-redundancy": "^1.1.0",
"@iconify/types": "^1.0.12",
"@iconify/utils": "^1.0.23"
"@iconify/utils": "^1.0.24"
},
"devDependencies": {
"@types/jest": "^27.4.0",
"@types/node": "^17.0.10",
"@typescript-eslint/eslint-plugin": "^5.10.0",
"@typescript-eslint/eslint-plugin": "^5.15.0",
"cross-env": "^7.0.3",
"cross-fetch": "^3.1.5",
"eslint": "^8.7.0",
"eslint": "^8.11.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.4.7",
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"ts-node": "^10.7.0",
"typescript": "^4.5.5",
"unbuild": "^0.7.0"
"unbuild": "^0.6.9",
"vitest": "^0.5.9"
}
}

View File

@ -23,15 +23,22 @@ interface CallbackItem {
abort: IconifyIconLoaderAbort;
}
type PrefixCallbackItems = CallbackItem[];
type ProviderCallbackItems = Record<string, PrefixCallbackItems>;
// Records sorted by provider and prefix
// This export is only for unit testing, should not be used
export const callbacks: Record<
export const callbacks = Object.create(null) as Record<
string,
Record<string, CallbackItem[]>
> = Object.create(null);
const pendingUpdates: Record<string, Record<string, boolean>> = Object.create(
null
);
ProviderCallbackItems
>;
// List of provider/prefix combinations that need to be updated
type ProviderPendingUpdates = Record<string, boolean>;
const pendingUpdates = Object.create(null) as Record<
string,
ProviderPendingUpdates
>;
/**
* Remove callback
@ -57,7 +64,9 @@ function removeCallback(sources: IconifyIconSource[], id: number): void {
*/
export function updateCallbacks(provider: string, prefix: string): void {
if (pendingUpdates[provider] === void 0) {
pendingUpdates[provider] = Object.create(null);
pendingUpdates[provider] = Object.create(
null
) as ProviderPendingUpdates;
}
const providerPendingUpdates = pendingUpdates[provider];
@ -176,7 +185,7 @@ export function storeCallback(
const provider = source.provider;
const prefix = source.prefix;
if (callbacks[provider] === void 0) {
callbacks[provider] = Object.create(null);
callbacks[provider] = Object.create(null) as ProviderCallbackItems;
}
const providerCallbacks = callbacks[provider];
if (providerCallbacks[prefix] === void 0) {

View File

@ -62,7 +62,7 @@ export function createAPIConfig(
/**
* Local storage
*/
const configStorage: Record<string, IconifyAPIConfig> = Object.create(null);
const configStorage = Object.create(null) as Record<string, IconifyAPIConfig>;
/**
* Redundancy for API servers.

View File

@ -59,11 +59,13 @@ export type IsPending = (icon: IconifyIconName) => boolean;
*
* [provider][prefix][icon] = time when icon was added to queue
*/
type PendingIcons = Record<string, number>;
const pendingIcons: Record<
type PrefixPendingIcons = Record<string, number>;
type ProviderPendingIcons = Record<string, PrefixPendingIcons>;
const pendingIcons = Object.create(null) as Record<
string,
Record<string, PendingIcons>
> = Object.create(null);
ProviderPendingIcons
>;
/**
* List of icons that are waiting to be loaded.
@ -75,15 +77,19 @@ const pendingIcons: Record<
*
* [provider][prefix] = array of icon names
*/
const iconsToLoad: Record<string, Record<string, string[]>> = Object.create(
null
);
type IconsToLoadPrefixItem = string[];
type IconsToLoadProviderItem = Record<string, IconsToLoadPrefixItem>;
const iconsToLoad = Object.create(null) as Record<
string,
IconsToLoadProviderItem
>;
// Flags to merge multiple synchronous icon requests in one asynchronous request
const loaderFlags: Record<string, Record<string, boolean>> = Object.create(
null
);
const queueFlags: Record<string, Record<string, boolean>> = Object.create(null);
type FlagsItem = Record<string, boolean>;
const loaderFlags = Object.create(null) as Record<string, FlagsItem>;
const queueFlags = Object.create(null) as Record<string, FlagsItem>;
/**
* Function called when new icons have been loaded
@ -91,7 +97,7 @@ const queueFlags: Record<string, Record<string, boolean>> = Object.create(null);
function loadedNewIcons(provider: string, prefix: string): void {
// Run only once per tick, possibly joining multiple API responses in one call
if (loaderFlags[provider] === void 0) {
loaderFlags[provider] = Object.create(null);
loaderFlags[provider] = Object.create(null) as FlagsItem;
}
const providerLoaderFlags = loaderFlags[provider];
if (!providerLoaderFlags[prefix]) {
@ -104,7 +110,7 @@ function loadedNewIcons(provider: string, prefix: string): void {
}
// Storage for errors for loadNewIcons(). Used to avoid spamming log with identical errors.
const errorsCache: Record<string, number> = Object.create(null);
const errorsCache = Object.create(null) as Record<string, number>;
/**
* Load icons
@ -125,17 +131,17 @@ function loadNewIcons(provider: string, prefix: string, icons: string[]): void {
// Create nested objects if needed
if (iconsToLoad[provider] === void 0) {
iconsToLoad[provider] = Object.create(null);
iconsToLoad[provider] = Object.create(null) as IconsToLoadProviderItem;
}
const providerIconsToLoad = iconsToLoad[provider];
if (queueFlags[provider] === void 0) {
queueFlags[provider] = Object.create(null);
queueFlags[provider] = Object.create(null) as FlagsItem;
}
const providerQueueFlags = queueFlags[provider];
if (pendingIcons[provider] === void 0) {
pendingIcons[provider] = Object.create(null);
pendingIcons[provider] = Object.create(null) as ProviderPendingIcons;
}
const providerPendingIcons = pendingIcons[provider];
@ -267,9 +273,13 @@ export const loadIcons: IconifyLoadIcons = (
}
// Get all sources for pending icons
const newIcons: Record<string, Record<string, string[]>> = Object.create(
null
);
type PrefixNewIconsList = string[];
type ProviderNewIconsList = Record<string, PrefixNewIconsList>;
const newIcons = Object.create(null) as Record<
string,
ProviderNewIconsList
>;
const sources: IconifyIconSource[] = [];
let lastProvider: string, lastPrefix: string;
@ -288,15 +298,19 @@ export const loadIcons: IconifyLoadIcons = (
});
if (pendingIcons[provider] === void 0) {
pendingIcons[provider] = Object.create(null);
pendingIcons[provider] = Object.create(
null
) as ProviderPendingIcons;
}
const providerPendingIcons = pendingIcons[provider];
if (providerPendingIcons[prefix] === void 0) {
providerPendingIcons[prefix] = Object.create(null);
providerPendingIcons[prefix] = Object.create(
null
) as PrefixPendingIcons;
}
if (newIcons[provider] === void 0) {
newIcons[provider] = Object.create(null);
newIcons[provider] = Object.create(null) as ProviderNewIconsList;
}
const providerNewIcons = newIcons[provider];
if (providerNewIcons[prefix] === void 0) {
@ -344,10 +358,10 @@ export const loadIcons: IconifyLoadIcons = (
* Cache for loadIcon promises
*/
type LoadIconResult = Promise<Required<IconifyIcon>>;
const iconsQueue: Record<string, LoadIconResult> = Object.create(null);
const iconsQueue = Object.create(null) as Record<string, LoadIconResult>;
export const loadIcon = (icon: IconifyIconName | string): LoadIconResult => {
if (typeof icon === 'string' && iconsQueue[icon]) {
if (typeof icon === 'string' && iconsQueue[icon] !== void 0) {
return iconsQueue[icon];
}

View File

@ -45,7 +45,7 @@ export interface IconifyAPIModule {
/**
* Local storate types and entries
*/
const storage: Record<string, IconifyAPIModule> = Object.create(null);
const storage = Object.create(null) as Record<string, IconifyAPIModule>;
/**
* Set API module

View File

@ -27,8 +27,10 @@ interface IconifyAPIInternalStorage {
config: IconifyAPIConfig;
redundancy: Redundancy;
}
const redundancyCache: Record<string, IconifyAPIInternalStorage> =
Object.create(null);
const redundancyCache = Object.create(null) as Record<
string,
IconifyAPIInternalStorage
>;
/**
* Get Redundancy instance for provider
@ -87,9 +89,7 @@ export function sendAPIQuery(
redundancy = initRedundancy(config);
// Use host instead of API provider (defaults to '')
const moduleKey = target.resources
? (target.resources[0] as string)
: '';
const moduleKey = target.resources ? target.resources[0] : '';
const api = getAPIModule(moduleKey);
if (api) {
send = api.send;

View File

@ -107,7 +107,7 @@ function setCount(
value: number
): boolean {
try {
storage.setItem(countKey, value + '');
storage.setItem(countKey, value.toString());
count[key] = value;
return true;
} catch (err) {
@ -156,7 +156,7 @@ function destroyCache(storage: typeof localStorage): void {
try {
const total = getCount(storage);
for (let i = 0; i < total; i++) {
storage.removeItem(cachePrefix + i);
storage.removeItem(cachePrefix + i.toString());
}
} catch (err) {
//
@ -184,7 +184,7 @@ export const loadCache: LoadIconsCache = (): void => {
// Get one item from storage
const getItem = (index: number): boolean => {
const name = cachePrefix + index;
const name = cachePrefix + index.toString();
const item = func.getItem(name);
if (typeof item !== 'string') {
@ -196,7 +196,7 @@ export const loadCache: LoadIconsCache = (): void => {
let valid = true;
try {
// Parse, check time stamp
const data = JSON.parse(item as string) as StoredItem;
const data = JSON.parse(item) as StoredItem;
if (
typeof data !== 'object' ||
typeof data.cached !== 'number' ||
@ -301,7 +301,7 @@ export const storeCache: CacheIcons = (
provider,
data,
};
func.setItem(cachePrefix + index, JSON.stringify(item));
func.setItem(cachePrefix + index.toString(), JSON.stringify(item));
} catch (err) {
return false;
}

View File

@ -32,7 +32,7 @@ export function listToIcons(
* Get all providers
*/
export function getProviders(list: IconifyIconName[]): string[] {
const providers: Record<string, boolean> = Object.create(null);
const providers = Object.create(null) as Record<string, boolean>;
list.forEach((icon) => {
providers[icon.provider] = true;
});

View File

@ -20,8 +20,10 @@ export function sortIcons(icons: IconifyIconName[]): SortedIcons {
missing: [],
pending: [],
};
const storage: Record<string, Record<string, IconStorage>> =
Object.create(null);
const storage = Object.create(null) as Record<
string,
Record<string, IconStorage>
>;
// Sort icons alphabetically to prevent duplicates and make sure they are sorted in API queries
icons.sort((a, b) => {
@ -55,7 +57,10 @@ export function sortIcons(icons: IconifyIconName[]): SortedIcons {
const name = icon.name;
if (storage[provider] === void 0) {
storage[provider] = Object.create(null);
storage[provider] = Object.create(null) as Record<
string,
IconStorage
>;
}
const providerStorage = storage[provider];

View File

@ -26,7 +26,10 @@ const storageVersion = 1;
/**
* Storage by provider and prefix
*/
let storage: Record<string, Record<string, IconStorage>> = Object.create(null);
let storage = Object.create(null) as Record<
string,
Record<string, IconStorage>
>;
/**
* Share storage
@ -71,8 +74,8 @@ export function newStorage(provider: string, prefix: string): IconStorage {
return {
provider,
prefix,
icons: Object.create(null),
missing: Object.create(null),
icons: Object.create(null) as IconStorage['icons'],
missing: Object.create(null) as IconStorage['missing'],
};
}
@ -81,7 +84,7 @@ export function newStorage(provider: string, prefix: string): IconStorage {
*/
export function getStorage(provider: string, prefix: string): IconStorage {
if (storage[provider] === void 0) {
storage[provider] = Object.create(null);
storage[provider] = Object.create(null) as Record<string, IconStorage>;
}
const providerStorage = storage[provider];
if (providerStorage[prefix] === void 0) {

View File

@ -0,0 +1,13 @@
const { defineConfig } = require('vitest/config');
module.exports = defineConfig({
resolve: {
mainFields: ['require'],
extensions: ['.cjs'],
},
test: {
globals: true,
watch: false,
include: ['**/tests/*-test.ts'],
},
});

View File

@ -0,0 +1,9 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
watch: false,
include: ['**/tests/*-test.ts'],
},
});

View File

@ -17,8 +17,8 @@
"lint": "eslint --fix src/**/*.ts",
"prebuild": "npm run lint && npm run clean",
"build": "unbuild",
"test:jest-cjs": "jest --clearCache && jest --runInBand --config=jest.config.cjs",
"test:jest-esm": "jest --clearCache && cross-env NODE_OPTIONS=--experimental-vm-modules npx jest --runInBand --config=jest.config.mjs",
"test:jest-cjs": "jest --clearCache && jest --runInBand --config=jest.config.cjs",
"test:jest-esm": "jest --clearCache && cross-env NODE_OPTIONS=--experimental-vm-modules npx jest --runInBand --config=jest.config.mjs",
"test": "npm run test:jest-cjs && npm run test:jest-esm",
"vitest:cjs": "vitest --config vitest.config.cjs",
"vitest:esm": "vitest --config vitest.config.mjs",

View File

@ -2,7 +2,6 @@
"extends": "../tsconfig.json",
"compilerOptions": {
"types": ["node", "jest"],
"rootDir": ".",
"outDir": "../tests-compiled",
}
"rootDir": "."
}
}