diff --git a/.eslintrc.json b/.eslintrc.json index b69c5c16e2..9c3d4efbbf 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -86,9 +86,7 @@ "overrides": [ { "files": "*.ts", - "plugins": ["expect-type"], "extends": [ - "plugin:expect-type/recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended-type-checked", "plugin:@typescript-eslint/stylistic-type-checked", diff --git a/package-lock.json b/package-lock.json index 0440b2dd9a..6fada09d32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,6 @@ "@vitest/coverage-v8": "^2.1.8", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-expect-type": "^0.6.2", "eslint-plugin-jsdoc": "^50.6.1", "eslint-plugin-n": "^17.15.1", "eslint-plugin-unicorn": "^56.0.1", @@ -3108,25 +3107,6 @@ "eslint": ">=8" } }, - "node_modules/eslint-plugin-expect-type": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-expect-type/-/eslint-plugin-expect-type-0.6.2.tgz", - "integrity": "sha512-XWgtpplzr6GlpPUFG9ZApnSTv7QJXAPNN6hNmrlleVVCkAK23f/3E2BiCoA3Xtb0rIKfVKh7TLe+D1tcGt8/1w==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "^6.10.0 || ^7.0.1 || ^8", - "fs-extra": "^11.1.1", - "get-tsconfig": "^4.8.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@typescript-eslint/parser": ">=6", - "eslint": ">=7", - "typescript": ">=4" - } - }, "node_modules/eslint-plugin-jsdoc": { "version": "50.6.1", "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.6.1.tgz", @@ -3573,20 +3553,6 @@ "node": ">= 6" } }, - "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4215,18 +4181,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -7233,15 +7187,6 @@ "dev": true, "license": "ISC" }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", diff --git a/package.json b/package.json index 57a61640e6..be8fea65f1 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,6 @@ "@vitest/coverage-v8": "^2.1.8", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-expect-type": "^0.6.2", "eslint-plugin-jsdoc": "^50.6.1", "eslint-plugin-n": "^17.15.1", "eslint-plugin-unicorn": "^56.0.1", diff --git a/src/api/extract.spec.ts b/src/api/extract.spec.ts index 943b0825f4..6fad33665e 100644 --- a/src/api/extract.spec.ts +++ b/src/api/extract.spec.ts @@ -1,4 +1,4 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, expectTypeOf } from 'vitest'; import * as fixtures from '../__fixtures__/fixtures.js'; import { load } from '../load-parse.js'; @@ -15,57 +15,86 @@ interface RedSelMultipleObject { describe('$.extract', () => { it('() : should extract values for selectors', () => { const $ = load(fixtures.eleven); - const $root = load(fixtures.eleven).root(); - // An empty object should lead to an empty extraction. + const $root = $.root(); - // $ExpectType ExtractedMap<{}> + // An empty object should lead to an empty extraction. + expectTypeOf($root.extract({})).toEqualTypeOf>(); const emptyExtract = $root.extract({}); expect(emptyExtract).toStrictEqual({}); - // Non-existent values should be undefined. - // $ExpectType ExtractedMap<{ foo: string; }> + // Non-existent values should be undefined. + expectTypeOf($root.extract({ foo: 'bar' })).toEqualTypeOf<{ + foo: string | undefined; + }>(); const simpleExtract = $root.extract({ foo: 'bar' }); expect(simpleExtract).toStrictEqual({ foo: undefined }); // Existing values should be extracted. - expect<{ red: string | undefined }>( - $root.extract({ red: '.red' }), - ).toStrictEqual({ - red: 'Four', - }); - expect( + expectTypeOf($root.extract({ red: '.red' })).toEqualTypeOf<{ + red: string | undefined; + }>(); + expect($root.extract({ red: '.red' })).toStrictEqual({ red: 'Four' }); + + expectTypeOf( $root.extract({ red: '.red', sel: '.sel' }), - ).toStrictEqual({ + ).toEqualTypeOf(); + expect($root.extract({ red: '.red', sel: '.sel' })).toStrictEqual({ red: 'Four', sel: 'Three', }); - // Descriptors for extractions should be supported - expect( + + // Descriptors for extractions should be supported. + expectTypeOf( + $root.extract({ + red: { selector: '.red' }, + sel: { selector: '.sel' }, + }), + ).toEqualTypeOf(); + expect( $root.extract({ red: { selector: '.red' }, sel: { selector: '.sel' }, }), ).toStrictEqual({ red: 'Four', sel: 'Three' }); - // Should support extraction of multiple values. - // $ExpectType ExtractedMap<{ red: [string]; sel: [string]; }> + // Should support extraction of multiple values. + expectTypeOf( + $root.extract({ + red: ['.red'], + sel: ['.sel'], + }), + ).toEqualTypeOf<{ red: string[]; sel: string[] }>(); const multipleExtract = $root.extract({ red: ['.red'], sel: ['.sel'], }); - expect(multipleExtract).toStrictEqual({ + expectTypeOf(multipleExtract).toEqualTypeOf(); + expect(multipleExtract).toStrictEqual({ red: ['Four', 'Five', 'Nine'], sel: ['Three', 'Nine', 'Eleven'], }); + // Should support custom `prop`s. - expect( + expectTypeOf( + $root.extract({ + red: { selector: '.red', value: 'outerHTML' }, + sel: { selector: '.sel', value: 'tagName' }, + }), + ).toEqualTypeOf(); + expect( $root.extract({ red: { selector: '.red', value: 'outerHTML' }, sel: { selector: '.sel', value: 'tagName' }, }), ).toStrictEqual({ red: '
  • Four
  • ', sel: 'LI' }); + // Should support custom `prop`s for multiple values. - expect<{ red: string[] }>( + expectTypeOf( + $root.extract({ + red: [{ selector: '.red', value: 'outerHTML' }], + }), + ).toEqualTypeOf<{ red: string[] }>(); + expect( $root.extract({ red: [{ selector: '.red', value: 'outerHTML' }], }), @@ -76,8 +105,17 @@ describe('$.extract', () => { '
  • Nine
  • ', ], }); + // Should support custom extraction functions. - expect<{ red: string | undefined }>( + expectTypeOf( + $root.extract({ + red: { + selector: '.red', + value: (el, key) => `${key}=${$(el).text()}`, + }, + }), + ).toEqualTypeOf<{ red: string | undefined }>(); + expect( $root.extract({ red: { selector: '.red', @@ -85,8 +123,19 @@ describe('$.extract', () => { }, }), ).toStrictEqual({ red: 'red=Four' }); + // Should support custom extraction functions for multiple values. - expect<{ red: string[] }>( + expectTypeOf( + $root.extract({ + red: [ + { + selector: '.red', + value: (el, key) => `${key}=${$(el).text()}`, + }, + ], + }), + ).toEqualTypeOf<{ red: string[] }>(); + expect( $root.extract({ red: [ { @@ -96,9 +145,21 @@ describe('$.extract', () => { ], }), ).toStrictEqual({ red: ['red=Four', 'red=Five', 'red=Nine'] }); - // Should support extraction objects - // $ExpectType ExtractedMap<{ section: { selector: string; value: { red: string; sel: string; }; }; }> + // Should support extraction objects. + expectTypeOf( + $root.extract({ + section: { + selector: 'ul:nth(1)', + value: { + red: '.red', + sel: '.blue', + }, + }, + }), + ).toEqualTypeOf<{ + section: { red: string | undefined; sel: string | undefined } | undefined; + }>(); const subExtractObject = $root.extract({ section: { selector: 'ul:nth(1)', @@ -108,10 +169,10 @@ describe('$.extract', () => { }, }, }); - - expect<{ section: RedSelObject | undefined }>( - subExtractObject, - ).toStrictEqual({ + expectTypeOf(subExtractObject).toEqualTypeOf<{ + section: RedSelObject | undefined; + }>(); + expect(subExtractObject).toStrictEqual({ section: { red: 'Five', sel: 'Seven', diff --git a/vitest.config.ts b/vitest.config.ts index 8b6dab2656..edbb5c0a5d 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -11,6 +11,10 @@ const config: ViteUserConfig = defineConfig({ '*.config.ts', ], }, + typecheck: { + enabled: true, + include: ['src/api/extract.spec.ts'], + }, }, });