From 782075a123859ab05fead446fc4f21d3d702a6ae Mon Sep 17 00:00:00 2001 From: Timofey Kachalov Date: Sun, 7 Dec 2025 12:42:57 +0400 Subject: [PATCH 1/2] Version 4.2.2 (#1345) --- .github/workflows/ci.yml | 4 +- CHANGELOG.md | 4 + CLAUDE.md | 3 +- README.md | 1 - package.json | 13 +- src/JavaScriptObfuscator.ts | 6 + src/constants/ProAdvertiseMessage.ts | 5 + src/enums/logger/LoggingMessage.ts | 6 +- src/interfaces/logger/ILogger.ts | 6 + src/logger/Logger.ts | 7 + src/utils/AdvertisementUtils.ts | 228 ++++++++++++++++++ test/index.spec.ts | 1 + .../utils/AdvertisementUtils.spec.ts | 213 ++++++++++++++++ yarn.lock | 102 +++++++- 14 files changed, 576 insertions(+), 23 deletions(-) create mode 100644 src/constants/ProAdvertiseMessage.ts create mode 100644 src/utils/AdvertisementUtils.ts create mode 100644 test/unit-tests/utils/AdvertisementUtils.spec.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6bb2352bf..effb6921e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: JavaScript Obfuscator CI on: push: - branches: [master] + branches: [master, release-**] pull_request: - branches: [master] + branches: [master, release-**] schedule: - cron: '0 1 * * *' diff --git a/CHANGELOG.md b/CHANGELOG.md index 510fd350d..1b26e768f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ Change Log +v4.2.2 +--- +* Add JavaScript Obfuscator PRO advertisement message + v4.2.1 --- * Downgrade `multimatch` version to avoid esm errors diff --git a/CLAUDE.md b/CLAUDE.md index e55ec6c9c..3236bb57e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ **JavaScript Obfuscator** is a powerful, enterprise-grade code obfuscation tool for JavaScript and Node.js applications. It transforms readable JavaScript code into a protected, difficult-to-understand format while maintaining full functionality. The project is widely used for protecting intellectual property and preventing reverse engineering. -- **Version**: 4.1.1 +- **Version**: 5.0.0 - **Author**: Timofey Kachalov (@sanex3339) - **License**: BSD-2-Clause - **Repository**: https://github.com/javascript-obfuscator/javascript-obfuscator @@ -1423,7 +1423,6 @@ Use [grunt-contrib-obfuscator](https://github.com/javascript-obfuscator/grunt-co - **GitHub Issues**: Bug reports and feature requests - **GitHub Discussions**: Questions and general discussion -- **OpenCollective**: Financial support and sponsorship - **GitHub Sponsors**: Direct sponsorship ## License diff --git a/README.md b/README.md index a1dae1340..5c9da8780 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ #### You can support this project by donating: * (Github) https://github.com/sponsors/sanex3339 -* (OpenCollective) https://opencollective.com/javascript-obfuscator Huge thanks to all supporters! diff --git a/package.json b/package.json index ebdd473fd..a97b0200d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "javascript-obfuscator", - "version": "4.2.1", + "version": "4.2.2", "description": "JavaScript obfuscator", "keywords": [ "obfuscator", @@ -29,6 +29,7 @@ "chance": "1.1.13", "class-validator": "0.14.3", "commander": "12.1.0", + "conf": "15.0.2", "eslint-scope": "8.4.0", "eslint-visitor-keys": "4.2.1", "fast-deep-equal": "3.1.3", @@ -37,7 +38,6 @@ "md5": "2.3.0", "mkdirp": "3.0.1", "multimatch": "5.0.0", - "opencollective-postinstall": "2.0.3", "process": "0.11.10", "reflect-metadata": "0.2.2", "source-map-support": "0.5.21", @@ -124,7 +124,6 @@ "prettier:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"", "format": "yarn run prettier && yarn run eslint --fix", "git:addFiles": "git add .", - "postinstall": "opencollective-postinstall", "precommit": "yarn run eslint", "prepublishOnly": "yarn run build && yarn run build:typings", "prepare": "husky install" @@ -137,11 +136,5 @@ "Dmitry Zamotkin (https://github.com/zamotkin)" ], "license": "BSD-2-Clause", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/javascript-obfuscator" - }, - "collective": { - "url": "https://opencollective.com/javascript-obfuscator" - } + "packageManager": "yarn@1.22.21+sha512.ca75da26c00327d26267ce33536e5790f18ebd53266796fbb664d2a4a5116308042dd8ee7003b276a20eace7d3c5561c3577bdd71bcb67071187af124779620a" } diff --git a/src/JavaScriptObfuscator.ts b/src/JavaScriptObfuscator.ts index f6f91a5dd..53381b977 100644 --- a/src/JavaScriptObfuscator.ts +++ b/src/JavaScriptObfuscator.ts @@ -28,6 +28,7 @@ import { ecmaVersion } from './constants/EcmaVersion'; import { ASTParserFacade } from './ASTParserFacade'; import { NodeGuards } from './node/NodeGuards'; import { Utils } from './utils/Utils'; +import { AdvertisementUtils } from './utils/AdvertisementUtils'; @injectable() export class JavaScriptObfuscator implements IJavaScriptObfuscator { @@ -157,6 +158,11 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator { * @returns {IObfuscationResult} */ public obfuscate(sourceCode: string): IObfuscationResult { + if (AdvertisementUtils.shouldShowAdvertisement()) { + this.logger.advertise(LoggingMessage.JavaScriptObfuscatorProAdFirstPart); + this.logger.advertise(LoggingMessage.JavaScriptObfuscatorProAdSecondPart); + } + if (typeof sourceCode !== 'string') { sourceCode = ''; } diff --git a/src/constants/ProAdvertiseMessage.ts b/src/constants/ProAdvertiseMessage.ts new file mode 100644 index 000000000..3a69e4f9e --- /dev/null +++ b/src/constants/ProAdvertiseMessage.ts @@ -0,0 +1,5 @@ +export const proAdvertiseMessageFirstPart = `🛡️ JavaScript Obfuscator Pro is now available — with powerful Virtual Machine-based obfuscation +(bytecode virtualization, anti-decompilation, unique opcode and VM structure each compilation, and more).`; + +export const proAdvertiseMessageSecondPart = + '👉️ Get your API key at https://obfuscator.io and start using Virtual Machine obfuscation with javascript-obfuscator package.'; diff --git a/src/enums/logger/LoggingMessage.ts b/src/enums/logger/LoggingMessage.ts index 2a2ebe6af..1227bf78e 100644 --- a/src/enums/logger/LoggingMessage.ts +++ b/src/enums/logger/LoggingMessage.ts @@ -1,3 +1,5 @@ +import { proAdvertiseMessageFirstPart, proAdvertiseMessageSecondPart } from '../../constants/ProAdvertiseMessage'; + export enum LoggingMessage { EmptySourceCode = 'Empty source code. Obfuscation canceled...', ObfuscationCompleted = 'Obfuscation completed. Total time: %s sec.', @@ -5,5 +7,7 @@ export enum LoggingMessage { RandomGeneratorSeed = 'Random generator seed: %s...', CodeTransformationStage = 'Code transformation stage: %s...', NodeTransformationStage = 'AST transformation stage: %s...', - Version = 'Version: %s' + Version = 'Version: %s', + JavaScriptObfuscatorProAdFirstPart = proAdvertiseMessageFirstPart, + JavaScriptObfuscatorProAdSecondPart = proAdvertiseMessageSecondPart } diff --git a/src/interfaces/logger/ILogger.ts b/src/interfaces/logger/ILogger.ts index f186f5029..3977ae814 100644 --- a/src/interfaces/logger/ILogger.ts +++ b/src/interfaces/logger/ILogger.ts @@ -18,4 +18,10 @@ export interface ILogger { * @param {string | number} value */ warn(loggingMessage: LoggingMessage, value?: string | number): void; + + /** + * @param {LoggingMessage} loggingMessage + * @param {string | number} value + */ + advertise(loggingMessage: LoggingMessage): void; } diff --git a/src/logger/Logger.ts b/src/logger/Logger.ts index 5b706cb16..31b07ed98 100644 --- a/src/logger/Logger.ts +++ b/src/logger/Logger.ts @@ -90,4 +90,11 @@ export class Logger implements ILogger { Logger.log(Logger.colorWarn, LoggingPrefix.Base, loggingMessage, value); } + + /** + * @param {LoggingMessage} loggingMessage + */ + public advertise(loggingMessage: LoggingMessage): void { + Logger.log(Logger.colorInfo, LoggingPrefix.Base, loggingMessage); + } } diff --git a/src/utils/AdvertisementUtils.ts b/src/utils/AdvertisementUtils.ts new file mode 100644 index 000000000..f9c5c6008 --- /dev/null +++ b/src/utils/AdvertisementUtils.ts @@ -0,0 +1,228 @@ +/** + * Utility class for managing PRO advertisement display + * - Limits display to first N times + * - Skips display in CI environments + * - Only works in Node.js (returns false in browser) + */ +export class AdvertisementUtils { + /** + * Maximum number of times to show the advertisement + */ + private static readonly maxDisplayCount: number = 5; + + /** + * Storage key for the display count + */ + private static readonly storageKey: string = 'adDisplayCount'; + + /** + * Storage key for the timestamp of first display + */ + private static readonly timestampKey: string = 'adFirstDisplayTime'; + + /** + * Reset period in milliseconds (3 days) + */ + private static readonly resetPeriodMs: number = 3 * 24 * 60 * 60 * 1000; + + /** + * Common CI environment variables to detect + */ + private static readonly ciEnvVars: string[] = [ + 'CI', + 'CONTINUOUS_INTEGRATION', + 'GITHUB_ACTIONS', + 'GITLAB_CI', + 'TRAVIS', + 'CIRCLECI', + 'JENKINS_URL', + 'HUDSON_URL', + 'TEAMCITY_VERSION', + 'BUILDKITE', + 'TF_BUILD', // Azure Pipelines + 'BITBUCKET_BUILD_NUMBER', + 'CODEBUILD_BUILD_ID', // AWS CodeBuild + 'DRONE', + 'HEROKU_TEST_RUN_ID', + 'NETLIFY', + 'VERCEL', + 'NOW_BUILDER', // Vercel (legacy) + 'RENDER', + 'CODESANDBOX_SSE', + 'STACKBLITZ' + ]; + + /** + * Cached conf instance + */ + private static config: any = null; + + /** + * Check if running in a CI environment + */ + public static isCI(): boolean { + if (!this.isNodeEnvironment()) { + return false; + } + + return this.ciEnvVars.some((envVar) => { + const value = process.env[envVar]; + + return value !== undefined && value !== '' && value !== '0' && value !== 'false'; + }); + } + + /** + * Check if advertisement should be displayed + * Returns true if: + * - Running in Node.js (not browser) + * - Not in CI environment + * - Display count is less than maxDisplayCount + * + * Also increments the display count if returning true + * + * In browser environments, always returns false + */ + public static shouldShowAdvertisement(): boolean { + // Don't show in browser - only Node.js CLI + if (!this.isNodeEnvironment()) { + return false; + } + + // Don't show in CI environments + if (this.isCI()) { + return false; + } + + if (!process.stdout.isTTY) { + return false; + } + + // Initialize config if needed + const config = this.getConfig(); + + if (!config) { + return false; + } + + // Check if reset period has passed (3 days) + const firstDisplayTime = this.getFirstDisplayTime(config); + const now = Date.now(); + + if (firstDisplayTime && now - firstDisplayTime >= this.resetPeriodMs) { + // Reset counter after 3 days + this.resetDisplayData(config); + } + + // Check display count + const count = this.getDisplayCount(config); + + if (count >= this.maxDisplayCount) { + return false; + } + + // Set first display time if not set + if (!firstDisplayTime || now - firstDisplayTime >= this.resetPeriodMs) { + this.setFirstDisplayTime(config, now); + } + + // Increment count for next time + this.setDisplayCount(config, count + 1); + + return true; + } + + /** + * Check if running in Node.js environment + */ + private static isNodeEnvironment(): boolean { + return typeof process !== 'undefined' && process.versions?.node !== undefined; + } + + /** + * Get or create conf instance + */ + private static getConfig(): any { + if (this.config) { + return this.config; + } + + if (typeof window === 'undefined') { + try { + // Dynamic import to avoid bundling in browser + // eslint-disable-next-line no-eval + const Conf = eval('require')('conf').default; + + this.config = new Conf({ + projectName: 'javascript-obfuscator' + }); + + return this.config; + } catch { + return null; + } + } + + return null; + } + + /** + * Get current display count from config + */ + private static getDisplayCount(config: any): number { + try { + const count = config.get(this.storageKey, 0); + + return typeof count === 'number' ? count : 0; + } catch { + return 0; + } + } + + /** + * Set display count in config + */ + private static setDisplayCount(config: any, count: number): void { + try { + config.set(this.storageKey, count); + } catch { + // Ignore errors + } + } + + /** + * Get first display timestamp from config + */ + private static getFirstDisplayTime(config: any): number | null { + try { + const timestamp = config.get(this.timestampKey, null); + + return typeof timestamp === 'number' ? timestamp : null; + } catch { + return null; + } + } + + /** + * Set first display timestamp in config + */ + private static setFirstDisplayTime(config: any, timestamp: number): void { + try { + config.set(this.timestampKey, timestamp); + } catch { + // Ignore errors + } + } + + /** + * Reset display data (count and timestamp) + */ + private static resetDisplayData(config: any): void { + try { + config.delete(this.storageKey); + config.delete(this.timestampKey); + } catch { + // Ignore errors + } + } +} diff --git a/test/index.spec.ts b/test/index.spec.ts index 4c585766c..f156f832e 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -42,6 +42,7 @@ import './unit-tests/storages/identifier-names-cache/PropertyIdentifierNamesCach import './unit-tests/storages/string-array-transformers/literal-nodes-cache/LiteralNodesCacheStorage.spec'; import './unit-tests/storages/string-array-transformers/string-array/StringArrayStorage.spec'; import './unit-tests/storages/string-array-transformers/visited-lexical-scope-nodes-stack/VisitedLexicalScopeNodesStackStorage.spec'; +import './unit-tests/utils/AdvertisementUtils.spec'; import './unit-tests/utils/ArrayUtils.spec'; import './unit-tests/utils/CryptUtils.spec'; import './unit-tests/utils/CryptUtilsStringArray.spec'; diff --git a/test/unit-tests/utils/AdvertisementUtils.spec.ts b/test/unit-tests/utils/AdvertisementUtils.spec.ts new file mode 100644 index 000000000..b110e2f19 --- /dev/null +++ b/test/unit-tests/utils/AdvertisementUtils.spec.ts @@ -0,0 +1,213 @@ +import { assert } from 'chai'; + +import { AdvertisementUtils } from '../../../src/utils/AdvertisementUtils'; + +describe('AdvertisementUtils', () => { + describe('isCI', () => { + const originalEnv = { ...process.env }; + + afterEach(() => { + // Restore original environment + process.env = { ...originalEnv }; + }); + + describe('Variant #1: CI environment variable set', () => { + it('should return true when CI=true', () => { + process.env.CI = 'true'; + assert.isTrue(AdvertisementUtils.isCI()); + }); + + it('should return true when CI=1', () => { + process.env.CI = '1'; + assert.isTrue(AdvertisementUtils.isCI()); + }); + + it('should return true when GITHUB_ACTIONS is set', () => { + process.env.GITHUB_ACTIONS = 'true'; + assert.isTrue(AdvertisementUtils.isCI()); + }); + + it('should return true when TRAVIS is set', () => { + process.env.TRAVIS = 'true'; + assert.isTrue(AdvertisementUtils.isCI()); + }); + + it('should return true when GITLAB_CI is set', () => { + process.env.GITLAB_CI = 'true'; + assert.isTrue(AdvertisementUtils.isCI()); + }); + + it('should return true when JENKINS_URL is set', () => { + process.env.JENKINS_URL = 'http://jenkins.example.com'; + assert.isTrue(AdvertisementUtils.isCI()); + }); + }); + + describe('Variant #2: CI environment variable not set or false', () => { + beforeEach(() => { + // Clear all CI-related env vars + delete process.env.CI; + delete process.env.CONTINUOUS_INTEGRATION; + delete process.env.GITHUB_ACTIONS; + delete process.env.GITLAB_CI; + delete process.env.TRAVIS; + delete process.env.CIRCLECI; + delete process.env.JENKINS_URL; + delete process.env.BUILDKITE; + delete process.env.TF_BUILD; + }); + + it('should return false when no CI env vars are set', () => { + assert.isFalse(AdvertisementUtils.isCI()); + }); + + it('should return false when CI=false', () => { + process.env.CI = 'false'; + assert.isFalse(AdvertisementUtils.isCI()); + }); + + it('should return false when CI=0', () => { + process.env.CI = '0'; + assert.isFalse(AdvertisementUtils.isCI()); + }); + + it('should return false when CI is empty string', () => { + process.env.CI = ''; + assert.isFalse(AdvertisementUtils.isCI()); + }); + }); + }); + + describe('shouldShowAdvertisement', () => { + const originalEnv = { ...process.env }; + const originalIsTTY = process.stdout.isTTY; + + afterEach(() => { + process.env = { ...originalEnv }; + process.stdout.isTTY = originalIsTTY; + }); + + describe('Variant #1: non-TTY environment', () => { + it('should return false when stdout is not a TTY', () => { + process.stdout.isTTY = false; + // Clear CI env vars + delete process.env.CI; + assert.isFalse(AdvertisementUtils.shouldShowAdvertisement()); + }); + }); + + describe('Variant #2: CI environment', () => { + it('should return false in CI environment', () => { + process.stdout.isTTY = true; + process.env.CI = 'true'; + assert.isFalse(AdvertisementUtils.shouldShowAdvertisement()); + }); + }); + + describe('Variant #3: display counter and reset', () => { + let config: any; + + before(() => { + // Get config instance using eval('require') - same as AdvertisementUtils + // conf is an ES Module, so we need to access .default + // eslint-disable-next-line no-eval + const Conf = eval('require')('conf').default; + config = new Conf({ projectName: 'javascript-obfuscator' }); + }); + + beforeEach(() => { + // Clear ad-related config before each test + config.delete('adDisplayCount'); + config.delete('adFirstDisplayTime'); + // Reset cached config in AdvertisementUtils + (AdvertisementUtils as any).config = null; + // Ensure TTY and non-CI environment + process.stdout.isTTY = true; + delete process.env.CI; + delete process.env.GITHUB_ACTIONS; + delete process.env.TRAVIS; + delete process.env.GITLAB_CI; + }); + + afterEach(() => { + // Clean up + config.delete('adDisplayCount'); + config.delete('adFirstDisplayTime'); + (AdvertisementUtils as any).config = null; + }); + + it('should return true for first 5 calls', () => { + for (let i = 0; i < 5; i++) { + assert.isTrue(AdvertisementUtils.shouldShowAdvertisement(), `Call ${i + 1} should return true`); + } + }); + + it('should return false after 5 calls', () => { + // Exhaust the counter + for (let i = 0; i < 5; i++) { + AdvertisementUtils.shouldShowAdvertisement(); + } + + // 6th call should return false + assert.isFalse(AdvertisementUtils.shouldShowAdvertisement()); + }); + + it('should increment counter on each call', () => { + AdvertisementUtils.shouldShowAdvertisement(); + assert.strictEqual(config.get('adDisplayCount'), 1); + + AdvertisementUtils.shouldShowAdvertisement(); + assert.strictEqual(config.get('adDisplayCount'), 2); + + AdvertisementUtils.shouldShowAdvertisement(); + assert.strictEqual(config.get('adDisplayCount'), 3); + }); + + it('should set first display timestamp on first call', () => { + const beforeTime = Date.now(); + AdvertisementUtils.shouldShowAdvertisement(); + const afterTime = Date.now(); + + const timestamp = config.get('adFirstDisplayTime'); + assert.isNumber(timestamp); + assert.isAtLeast(timestamp, beforeTime); + assert.isAtMost(timestamp, afterTime); + }); + + it('should reset counter after 3 days', () => { + // Exhaust counter + for (let i = 0; i < 5; i++) { + AdvertisementUtils.shouldShowAdvertisement(); + } + assert.isFalse(AdvertisementUtils.shouldShowAdvertisement()); + + // Simulate 3 days passing by setting old timestamp + const threeDaysAgo = Date.now() - 3 * 24 * 60 * 60 * 1000 - 1000; + config.set('adFirstDisplayTime', threeDaysAgo); + // Reset cached config + (AdvertisementUtils as any).config = null; + + // Should return true again after reset + assert.isTrue(AdvertisementUtils.shouldShowAdvertisement()); + // Counter should be reset to 1 + assert.strictEqual(config.get('adDisplayCount'), 1); + }); + + it('should not reset counter before 3 days', () => { + // Exhaust counter + for (let i = 0; i < 5; i++) { + AdvertisementUtils.shouldShowAdvertisement(); + } + + // Simulate 2 days passing (less than 3 days) + const twoDaysAgo = Date.now() - 2 * 24 * 60 * 60 * 1000; + config.set('adFirstDisplayTime', twoDaysAgo); + // Reset cached config + (AdvertisementUtils as any).config = null; + + // Should still return false + assert.isFalse(AdvertisementUtils.shouldShowAdvertisement()); + }); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 93f02ef83..c8a36b504 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1053,6 +1053,13 @@ ajv-formats@^2.1.1: dependencies: ajv "^8.0.0" +ajv-formats@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-3.0.1.tgz#3d5dc762bca17679c3c2ea7e90ad6b7532309578" + integrity sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ== + dependencies: + ajv "^8.0.0" + ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" @@ -1085,7 +1092,7 @@ ajv@^8.0.0: require-from-string "^2.0.2" uri-js "^4.2.2" -ajv@^8.9.0: +ajv@^8.17.1, ajv@^8.9.0: version "8.17.1" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== @@ -1273,6 +1280,14 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +atomically@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/atomically/-/atomically-2.1.0.tgz#5a3ce8ea5ab57b65df589a3b63ef7b753cc0af07" + integrity sha512-+gDffFXRW6sl/HCwbta7zK4uNqbPjv4YJEAdz7Vu+FLQHe77eZ4bvbJGi4hE0QPeJlMYMA3piXEr1UL3dAwx7Q== + dependencies: + stubborn-fs "^2.0.0" + when-exit "^2.1.4" + available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz" @@ -1622,6 +1637,21 @@ concat-map@0.0.1: resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +conf@15.0.2: + version "15.0.2" + resolved "https://registry.yarnpkg.com/conf/-/conf-15.0.2.tgz#b983be81227a304b9f885fde6c86c7fe5902dc9d" + integrity sha512-JBSrutapCafTrddF9dH3lc7+T2tBycGF4uPkI4Js+g4vLLEhG6RZcFi3aJd5zntdf5tQxAejJt8dihkoQ/eSJw== + dependencies: + ajv "^8.17.1" + ajv-formats "^3.0.1" + atomically "^2.0.3" + debounce-fn "^6.0.0" + dot-prop "^10.0.0" + env-paths "^3.0.0" + json-schema-typed "^8.0.1" + semver "^7.7.2" + uint8array-extras "^1.5.0" + config-chain@^1.1.13: version "1.1.13" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" @@ -1740,6 +1770,13 @@ data-view-byte-offset@^1.0.1: es-errors "^1.3.0" is-data-view "^1.0.1" +debounce-fn@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-6.0.0.tgz#558169aed853eb3cf3a17c0a2438e1a91a7ba44f" + integrity sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ== + dependencies: + mimic-function "^5.0.0" + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -1885,6 +1922,13 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dot-prop@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-10.1.0.tgz#91dbeb6771a9d2c31eab11ade3fdb1d83c4376c4" + integrity sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q== + dependencies: + type-fest "^5.0.0" + dunder-proto@^1.0.0, dunder-proto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" @@ -1940,6 +1984,11 @@ enhanced-resolve@^5.17.3: graceful-fs "^4.2.4" tapable "^2.2.0" +env-paths@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-3.0.0.tgz#2f1e89c2f6dbd3408e1b1711dd82d62e317f58da" + integrity sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A== + envinfo@^7.14.0: version "7.19.0" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.19.0.tgz#b4b4507a27e9900b0175f556167fd3a95f8623f1" @@ -3576,6 +3625,11 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +json-schema-typed@^8.0.1: + version "8.0.2" + resolved "https://registry.yarnpkg.com/json-schema-typed/-/json-schema-typed-8.0.2.tgz#e98ee7b1899ff4a184534d1f167c288c66bbeff4" + integrity sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" @@ -3777,6 +3831,11 @@ mime-types@^2.1.27: dependencies: mime-db "1.44.0" +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== + min-indent@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" @@ -4112,11 +4171,6 @@ once@^1.3.0: dependencies: wrappy "1" -opencollective-postinstall@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" - integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== - optionator@^0.8.1: version "0.8.3" resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" @@ -4634,7 +4688,7 @@ semver@^7.3.5: dependencies: lru-cache "^6.0.0" -semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3: +semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3, semver@^7.7.2: version "7.7.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== @@ -5018,6 +5072,18 @@ strip-json-comments@^3.1.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +stubborn-fs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/stubborn-fs/-/stubborn-fs-2.0.0.tgz#628750f81c51c44c04ef50fc70ed4d1caea4f1e9" + integrity sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA== + dependencies: + stubborn-utils "^1.0.1" + +stubborn-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stubborn-utils/-/stubborn-utils-1.0.2.tgz#0d9c58ab550f40936235056c7ea6febd925c4d41" + integrity sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg== + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" @@ -5066,6 +5132,11 @@ synckit@^0.9.1: "@pkgr/core" "^0.1.0" tslib "^2.6.2" +tagged-tag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tagged-tag/-/tagged-tag-1.0.0.tgz#a0b5917c2864cba54841495abfa3f6b13edcf4d6" + integrity sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng== + tapable@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz" @@ -5236,6 +5307,13 @@ type-fest@^0.8.0, type-fest@^0.8.1: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-fest@^5.0.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-5.3.0.tgz#9422125b3094b1087d8446ba151b72fb9f39411a" + integrity sha512-d9CwU93nN0IA1QL+GSNDdwLAu1Ew5ZjTwupvedwg3WdfoH6pIDvYQ2hV0Uc2nKBLPq7NB5apCx57MLS5qlmO5g== + dependencies: + tagged-tag "^1.0.0" + typed-array-buffer@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" @@ -5293,6 +5371,11 @@ typescript@5.9.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== +uint8array-extras@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/uint8array-extras/-/uint8array-extras-1.5.0.tgz#10d2a85213de3ada304fea1c454f635c73839e86" + integrity sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A== + unbox-primitive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" @@ -5449,6 +5532,11 @@ webpack@5.102.1: watchpack "^2.4.4" webpack-sources "^3.3.3" +when-exit@^2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/when-exit/-/when-exit-2.1.5.tgz#53fa4ffa2ba4c792213fb6617eb7d08f0dcb1a9f" + integrity sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg== + which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" From 448c72090c33ed3090d167697c7b6a94cbc548c6 Mon Sep 17 00:00:00 2001 From: sanex3339 Date: Sun, 7 Dec 2025 12:46:21 +0400 Subject: [PATCH 2/2] Adjust package.json and CI --- .github/workflows/ci.yml | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index effb6921e..635547b33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,7 @@ jobs: key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} - run: yarn install - run: yarn run build + - run: yarn run test:mocha-coverage - run: yarn run test:mocha-coverage:report - name: Coveralls uses: coverallsapp/github-action@master diff --git a/package.json b/package.json index a97b0200d..222185516 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "scripts": { "start": "yarn run watch", "webpack:prod": "webpack --config ./webpack/webpack.node.config.js --config ./webpack/webpack.browser.config.js --mode production", - "build": "yarn run webpack:prod && yarn run eslint && yarn test", + "build": "yarn run webpack:prod && yarn run eslint", "build:typings": "rm -rf ./typings && tsc --project src/tsconfig.typings.json", "watch": "webpack --config ./webpack/webpack.node.config.js --mode development --watch", "test:dev": "ts-node --type-check test/dev/dev.ts",