This commit is contained in:
2025-05-09 05:30:08 +02:00
parent 7bb10e7df4
commit 73367bad9e
5322 changed files with 1266973 additions and 313 deletions

View File

@@ -0,0 +1,108 @@
/*! simple-get. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
module.exports = simpleGet
const concat = require('simple-concat')
const decompressResponse = require('decompress-response') // excluded from browser build
const http = require('http')
const https = require('https')
const once = require('once')
const querystring = require('querystring')
const url = require('url')
const isStream = o => o !== null && typeof o === 'object' && typeof o.pipe === 'function'
function simpleGet (opts, cb) {
opts = Object.assign({ maxRedirects: 10 }, typeof opts === 'string' ? { url: opts } : opts)
cb = once(cb)
if (opts.url) {
const { hostname, port, protocol, auth, path } = url.parse(opts.url) // eslint-disable-line node/no-deprecated-api
delete opts.url
if (!hostname && !port && !protocol && !auth) opts.path = path // Relative redirect
else Object.assign(opts, { hostname, port, protocol, auth, path }) // Absolute redirect
}
const headers = { 'accept-encoding': 'gzip, deflate' }
if (opts.headers) Object.keys(opts.headers).forEach(k => (headers[k.toLowerCase()] = opts.headers[k]))
opts.headers = headers
let body
if (opts.body) {
body = opts.json && !isStream(opts.body) ? JSON.stringify(opts.body) : opts.body
} else if (opts.form) {
body = typeof opts.form === 'string' ? opts.form : querystring.stringify(opts.form)
opts.headers['content-type'] = 'application/x-www-form-urlencoded'
}
if (body) {
if (!opts.method) opts.method = 'POST'
if (!isStream(body)) opts.headers['content-length'] = Buffer.byteLength(body)
if (opts.json && !opts.form) opts.headers['content-type'] = 'application/json'
}
delete opts.body; delete opts.form
if (opts.json) opts.headers.accept = 'application/json'
if (opts.method) opts.method = opts.method.toUpperCase()
const originalHost = opts.hostname // hostname before potential redirect
const protocol = opts.protocol === 'https:' ? https : http // Support http/https urls
const req = protocol.request(opts, res => {
if (opts.followRedirects !== false && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
opts.url = res.headers.location // Follow 3xx redirects
delete opts.headers.host // Discard `host` header on redirect (see #32)
res.resume() // Discard response
const redirectHost = url.parse(opts.url).hostname // eslint-disable-line node/no-deprecated-api
// If redirected host is different than original host, drop headers to prevent cookie leak (#73)
if (redirectHost !== null && redirectHost !== originalHost) {
delete opts.headers.cookie
delete opts.headers.authorization
}
if (opts.method === 'POST' && [301, 302].includes(res.statusCode)) {
opts.method = 'GET' // On 301/302 redirect, change POST to GET (see #35)
delete opts.headers['content-length']; delete opts.headers['content-type']
}
if (opts.maxRedirects-- === 0) return cb(new Error('too many redirects'))
else return simpleGet(opts, cb)
}
const tryUnzip = typeof decompressResponse === 'function' && opts.method !== 'HEAD'
cb(null, tryUnzip ? decompressResponse(res) : res)
})
req.on('timeout', () => {
req.abort()
cb(new Error('Request timed out'))
})
req.on('error', cb)
if (isStream(body)) body.on('error', cb).pipe(req)
else req.end(body)
return req
}
simpleGet.concat = (opts, cb) => {
return simpleGet(opts, (err, res) => {
if (err) return cb(err)
concat(res, (err, data) => {
if (err) return cb(err)
if (opts.json) {
try {
data = JSON.parse(data.toString())
} catch (err) {
return cb(err, res, data)
}
}
cb(null, res, data)
})
})
}
;['get', 'post', 'put', 'patch', 'head', 'delete'].forEach(method => {
simpleGet[method] = (opts, cb) => {
if (typeof opts === 'string') opts = { url: opts }
return simpleGet(Object.assign({ method: method.toUpperCase() }, opts), cb)
}
})

View File

@@ -0,0 +1 @@
module.exports={A:{A:{"1":"A B","2":"K D mC","132":"E F"},B:{"1":"0 9 C L M G N O P Q H R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I"},C:{"1":"0 1 2 3 4 5 6 7 8 9 J PB K D E F A B C L M G N O P QB RB SB TB UB VB WB XB YB ZB aB bB cB dB eB fB gB hB iB jB kB lB mB nB oB pB qB rB sB tB uB vB MC wB NC xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R OC S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I PC EC QC RC oC pC","2":"nC LC qC rC"},D:{"1":"0 1 2 3 4 5 6 7 8 9 J PB K D E F A B C L M G N O P QB RB SB TB UB VB WB XB YB ZB aB bB cB dB eB fB gB hB iB jB kB lB mB nB oB pB qB rB sB tB uB vB MC wB NC xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I PC EC QC RC"},E:{"1":"J PB K D E F A B C L M G sC SC tC uC vC wC TC FC GC xC yC zC UC VC HC 0C IC WC XC YC ZC aC 1C JC bC cC dC eC fC 2C KC gC hC iC jC 3C"},F:{"1":"0 1 2 3 4 5 6 7 8 B C G N O P QB RB SB TB UB VB WB XB YB ZB aB bB cB dB eB fB gB hB iB jB kB lB mB nB oB pB qB rB sB tB uB vB wB xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R OC S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z FC kC 8C GC","2":"F 4C 5C 6C 7C"},G:{"1":"SC 9C lC AD","513":"E BD CD DD ED FD GD HD ID JD KD LD MD ND OD PD QD RD SD UC VC HC TD IC WC XC YC ZC aC UD JC bC cC dC eC fC VD KC gC hC iC jC"},H:{"4097":"WD"},I:{"1025":"LC J I XD YD ZD aD lC bD cD"},J:{"258":"D A"},K:{"2":"A","258":"B C FC kC GC","1025":"H"},L:{"1025":"I"},M:{"2049":"EC"},N:{"258":"A B"},O:{"258":"HC"},P:{"1025":"1 2 3 4 5 6 7 8 J dD eD fD gD hD TC iD jD kD lD mD IC JC KC nD"},Q:{"1":"oD"},R:{"1025":"pD"},S:{"1":"qD rD"}},B:1,C:"Basic console logging functions",D:true};

View File

@@ -0,0 +1,223 @@
/**
* @fileoverview Helpers to debug for code path analysis.
* @author Toru Nagashima
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const debug = require("debug")("eslint:code-path");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
* Gets id of a given segment.
* @param {CodePathSegment} segment A segment to get.
* @returns {string} Id of the segment.
*/
/* c8 ignore next */
// eslint-disable-next-line jsdoc/require-jsdoc -- Ignoring
function getId(segment) {
return segment.id + (segment.reachable ? "" : "!");
}
/**
* Get string for the given node and operation.
* @param {ASTNode} node The node to convert.
* @param {"enter" | "exit" | undefined} label The operation label.
* @returns {string} The string representation.
*/
function nodeToString(node, label) {
const suffix = label ? `:${label}` : "";
switch (node.type) {
case "Identifier":
return `${node.type}${suffix} (${node.name})`;
case "Literal":
return `${node.type}${suffix} (${node.value})`;
default:
return `${node.type}${suffix}`;
}
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
module.exports = {
/**
* A flag that debug dumping is enabled or not.
* @type {boolean}
*/
enabled: debug.enabled,
/**
* Dumps given objects.
* @param {...any} args objects to dump.
* @returns {void}
*/
dump: debug,
/**
* Dumps the current analyzing state.
* @param {ASTNode} node A node to dump.
* @param {CodePathState} state A state to dump.
* @param {boolean} leaving A flag whether or not it's leaving
* @returns {void}
*/
dumpState: !debug.enabled
? debug
: /* c8 ignore next */ function (node, state, leaving) {
for (let i = 0; i < state.currentSegments.length; ++i) {
const segInternal = state.currentSegments[i].internal;
if (leaving) {
const last = segInternal.nodes.length - 1;
if (
last >= 0 &&
segInternal.nodes[last] ===
nodeToString(node, "enter")
) {
segInternal.nodes[last] = nodeToString(
node,
void 0,
);
} else {
segInternal.nodes.push(nodeToString(node, "exit"));
}
} else {
segInternal.nodes.push(nodeToString(node, "enter"));
}
}
debug(
[
`${state.currentSegments.map(getId).join(",")})`,
`${node.type}${leaving ? ":exit" : ""}`,
].join(" "),
);
},
/**
* Dumps a DOT code of a given code path.
* The DOT code can be visualized with Graphvis.
* @param {CodePath} codePath A code path to dump.
* @returns {void}
* @see http://www.graphviz.org
* @see http://www.webgraphviz.com
*/
dumpDot: !debug.enabled
? debug
: /* c8 ignore next */ function (codePath) {
let text =
"\n" +
"digraph {\n" +
'node[shape=box,style="rounded,filled",fillcolor=white];\n' +
'initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];\n';
if (codePath.returnedSegments.length > 0) {
text +=
'final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];\n';
}
if (codePath.thrownSegments.length > 0) {
text +=
'thrown[label="✘",shape=circle,width=0.3,height=0.3,fixedsize=true];\n';
}
const traceMap = Object.create(null);
const arrows = this.makeDotArrows(codePath, traceMap);
// eslint-disable-next-line guard-for-in -- Want ability to traverse prototype
for (const id in traceMap) {
const segment = traceMap[id];
text += `${id}[`;
if (segment.reachable) {
text += 'label="';
} else {
text +=
'style="rounded,dashed,filled",fillcolor="#FF9800",label="<<unreachable>>\\n';
}
if (segment.internal.nodes.length > 0) {
text += segment.internal.nodes.join("\\n");
} else {
text += "????";
}
text += '"];\n';
}
text += `${arrows}\n`;
text += "}";
debug("DOT", text);
},
/**
* Makes a DOT code of a given code path.
* The DOT code can be visualized with Graphvis.
* @param {CodePath} codePath A code path to make DOT.
* @param {Object} traceMap Optional. A map to check whether or not segments had been done.
* @returns {string} A DOT code of the code path.
*/
makeDotArrows(codePath, traceMap) {
const stack = [[codePath.initialSegment, 0]];
const done = traceMap || Object.create(null);
let lastId = codePath.initialSegment.id;
let text = `initial->${codePath.initialSegment.id}`;
while (stack.length > 0) {
const item = stack.pop();
const segment = item[0];
const index = item[1];
if (done[segment.id] && index === 0) {
continue;
}
done[segment.id] = segment;
const nextSegment = segment.allNextSegments[index];
if (!nextSegment) {
continue;
}
if (lastId === segment.id) {
text += `->${nextSegment.id}`;
} else {
text += `;\n${segment.id}->${nextSegment.id}`;
}
lastId = nextSegment.id;
stack.unshift([segment, 1 + index]);
stack.push([nextSegment, 0]);
}
codePath.returnedSegments.forEach(finalSegment => {
if (lastId === finalSegment.id) {
text += "->final";
} else {
text += `;\n${finalSegment.id}->final`;
}
lastId = null;
});
codePath.thrownSegments.forEach(finalSegment => {
if (lastId === finalSegment.id) {
text += "->thrown";
} else {
text += `;\n${finalSegment.id}->thrown`;
}
lastId = null;
});
return `${text};`;
},
};

View File

@@ -0,0 +1 @@
module.exports={A:{A:{"2":"F A B mC","8":"K D E"},B:{"2":"0 9 C L M G N O P Q H R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I"},C:{"2":"0 1 2 3 4 5 6 7 8 9 nC LC J PB K D E F A B C L M G N O P QB RB SB TB UB VB WB XB YB ZB aB bB cB dB eB fB gB hB iB jB kB lB mB nB oB pB qB rB sB tB uB vB MC wB NC xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R OC S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I PC EC QC RC oC pC qC rC"},D:{"1":"1 2 3 4 5 6 7 8 J PB K D E F A B C L M G N O P QB RB SB TB UB VB WB XB YB ZB aB","2":"0 9 oB pB qB rB sB tB uB vB MC wB NC xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I PC EC QC RC","130":"bB cB dB eB fB gB hB iB jB kB lB mB nB"},E:{"1":"J PB K D E F A B C L M G SC tC uC vC wC TC FC GC xC yC zC UC VC HC 0C IC WC XC YC ZC aC 1C JC bC cC dC eC fC 2C KC gC hC iC jC 3C","2":"sC"},F:{"1":"1 2 3 4 5 F B C G N O P QB 4C 5C 6C 7C FC kC 8C GC","2":"0 aB bB cB dB eB fB gB hB iB jB kB lB mB nB oB pB qB rB sB tB uB vB wB xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R OC S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z","130":"6 7 8 RB SB TB UB VB WB XB YB ZB"},G:{"1":"E SC 9C lC AD BD CD DD ED FD GD HD ID JD KD LD MD ND OD PD QD RD SD UC VC HC TD IC WC XC YC ZC aC UD JC bC cC dC eC fC VD KC gC hC iC jC"},H:{"258":"WD"},I:{"1":"LC J aD lC bD cD","2":"I XD YD ZD"},J:{"1":"D A"},K:{"1":"A B C FC kC GC","2":"H"},L:{"130":"I"},M:{"2":"EC"},N:{"2":"A B"},O:{"2":"HC"},P:{"1":"J","130":"1 2 3 4 5 6 7 8 dD eD fD gD hD TC iD jD kD lD mD IC JC KC nD"},Q:{"2":"oD"},R:{"130":"pD"},S:{"2":"qD rD"}},B:2,C:"SVG fonts",D:true};

View File

@@ -0,0 +1,72 @@
{
"name": "enhanced-resolve",
"version": "5.18.1",
"author": "Tobias Koppers @sokra",
"description": "Offers a async require.resolve function. It's highly configurable.",
"files": [
"lib",
"types.d.ts",
"LICENSE"
],
"browser": {
"process": "./lib/util/process-browser.js",
"module": "./lib/util/module-browser.js"
},
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
},
"license": "MIT",
"devDependencies": {
"@types/graceful-fs": "^4.1.6",
"@types/jest": "^27.5.1",
"@types/node": "20.9.5",
"cspell": "4.2.8",
"eslint": "^7.9.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-jsdoc": "^30.5.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.4",
"husky": "^6.0.0",
"jest": "^27.5.1",
"lint-staged": "^10.4.0",
"memfs": "^3.2.0",
"prettier": "^2.1.2",
"tooling": "webpack/tooling#v1.23.1",
"typescript": "^5.3.3"
},
"engines": {
"node": ">=10.13.0"
},
"main": "lib/index.js",
"types": "types.d.ts",
"homepage": "http://github.com/webpack/enhanced-resolve",
"scripts": {
"lint": "yarn run code-lint && yarn run type-lint && yarn typings-test && yarn run special-lint && yarn run spelling",
"fix": "yarn run code-lint-fix && yarn run special-lint-fix",
"code-lint": "eslint --cache lib test",
"code-lint-fix": "eslint --cache lib test --fix",
"type-lint": "tsc",
"typings-test": "tsc -p tsconfig.types.test.json",
"type-report": "rimraf coverage && yarn cover:types && yarn cover:report && open-cli coverage/lcov-report/index.html",
"special-lint": "node node_modules/tooling/lockfile-lint && node node_modules/tooling/inherit-types && node node_modules/tooling/format-file-header && node node_modules/tooling/generate-types",
"special-lint-fix": "node node_modules/tooling/inherit-types --write && node node_modules/tooling/format-file-header --write && node node_modules/tooling/generate-types --write",
"pretty": "prettier --loglevel warn --write \"lib/**/*.{js,json}\" \"test/*.js\"",
"pretest": "yarn lint",
"spelling": "cspell \"**\"",
"test:only": "node_modules/.bin/jest",
"test:watch": "yarn test:only -- --watch",
"test:coverage": "yarn test:only -- --collectCoverageFrom=\"lib/**/*.js\" --coverage",
"test": "yarn test:coverage",
"precover": "yarn lint",
"prepare": "husky install"
},
"lint-staged": {
"*": "cspell --no-must-find-files",
"*.js": "eslint --cache"
},
"repository": {
"type": "git",
"url": "git://github.com/webpack/enhanced-resolve.git"
}
}

View File

@@ -0,0 +1,25 @@
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
type SubscribeWithSelector = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [
...Mps,
['zustand/subscribeWithSelector', never]
], Mcs>) => StateCreator<T, Mps, [['zustand/subscribeWithSelector', never], ...Mcs]>;
type Write<T, U> = Omit<T, keyof U> & U;
type WithSelectorSubscribe<S> = S extends {
getState: () => infer T;
} ? Write<S, StoreSubscribeWithSelector<T>> : never;
declare module '../vanilla.mjs' {
interface StoreMutators<S, A> {
['zustand/subscribeWithSelector']: WithSelectorSubscribe<S>;
}
}
type StoreSubscribeWithSelector<T> = {
subscribe: {
(listener: (selectedState: T, previousSelectedState: T) => void): () => void;
<U>(selector: (state: T) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
equalityFn?: (a: U, b: U) => boolean;
fireImmediately?: boolean;
}): () => void;
};
};
export declare const subscribeWithSelector: SubscribeWithSelector;
export {};

View File

@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = traverseFast;
var _index = require("../definitions/index.js");
const _skip = Symbol();
const _stop = Symbol();
function traverseFast(node, enter, opts) {
if (!node) return false;
const keys = _index.VISITOR_KEYS[node.type];
if (!keys) return false;
opts = opts || {};
const ret = enter(node, opts);
if (ret !== undefined) {
switch (ret) {
case _skip:
return false;
case _stop:
return true;
}
}
for (const key of keys) {
const subNode = node[key];
if (!subNode) continue;
if (Array.isArray(subNode)) {
for (const node of subNode) {
if (traverseFast(node, enter, opts)) return true;
}
} else {
if (traverseFast(subNode, enter, opts)) return true;
}
}
return false;
}
traverseFast.skip = _skip;
traverseFast.stop = _stop;
//# sourceMappingURL=traverseFast.js.map

View File

@@ -0,0 +1 @@
module.exports={A:{A:{"1":"F A B","2":"K D E mC"},B:{"1":"0 9 C L M G N O P Q H R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I"},C:{"1":"0 1 2 3 4 5 6 7 8 9 nC LC J PB K D E F A B C L M G N O P QB RB SB TB UB VB WB XB YB ZB aB bB cB dB eB fB gB hB iB jB kB lB mB nB oB pB qB rB sB tB uB vB MC wB NC xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R OC S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I PC EC QC RC oC pC qC rC"},D:{"1":"0 1 2 3 4 5 6 7 8 9 J PB K D E F A B C L M G N O P QB RB SB TB UB VB WB XB YB ZB aB bB cB dB eB fB gB hB iB jB kB lB mB nB oB pB qB rB sB tB uB vB MC wB NC xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z AB BB CB DB EB FB GB HB IB JB KB LB MB NB OB I PC EC QC RC"},E:{"1":"J PB K D E F A B C L M G sC SC tC uC vC wC TC FC GC xC yC zC UC VC HC 0C IC WC XC YC ZC aC 1C JC bC cC dC eC fC 2C KC gC hC iC jC 3C"},F:{"1":"0 1 2 3 4 5 6 7 8 F B C G N O P QB RB SB TB UB VB WB XB YB ZB aB bB cB dB eB fB gB hB iB jB kB lB mB nB oB pB qB rB sB tB uB vB wB xB yB zB 0B 1B 2B 3B 4B 5B 6B 7B 8B 9B AC BC CC DC Q H R OC S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z 4C 5C 6C 7C FC kC 8C GC"},G:{"1":"E SC 9C lC AD BD CD DD ED FD GD HD ID JD KD LD MD ND OD PD QD RD SD UC VC HC TD IC WC XC YC ZC aC UD JC bC cC dC eC fC VD KC gC hC iC jC"},H:{"1":"WD"},I:{"1":"LC J I XD YD ZD aD lC bD cD"},J:{"1":"D A"},K:{"1":"A B C H FC kC GC"},L:{"1":"I"},M:{"1":"EC"},N:{"1":"A B"},O:{"1":"HC"},P:{"1":"1 2 3 4 5 6 7 8 J dD eD fD gD hD TC iD jD kD lD mD IC JC KC nD"},Q:{"1":"oD"},R:{"1":"pD"},S:{"1":"qD rD"}},B:1,C:"XHTML served as application/xhtml+xml",D:true};

View File

@@ -0,0 +1,169 @@
import { beforeAll, describe, expect, it } from 'vitest';
import { createRef } from 'react';
import { render, screen } from '@testing-library/react';
import { pdfjs } from './index.test.js';
import Outline from './Outline.js';
import failingPdf from '../../../__mocks__/_failing_pdf.js';
import { loadPDF, makeAsyncCallback, muteConsole, restoreConsole } from '../../../test-utils.js';
import DocumentContext from './DocumentContext.js';
import type { PDFDocumentProxy } from 'pdfjs-dist';
import type { DocumentContextType } from './shared/types.js';
type PDFOutline = Awaited<ReturnType<PDFDocumentProxy['getOutline']>>;
const pdfFile = loadPDF('./../../__mocks__/_pdf.pdf');
const pdfFile2 = loadPDF('./../../__mocks__/_pdf2.pdf');
function renderWithContext(children: React.ReactNode, context: Partial<DocumentContextType>) {
const { rerender, ...otherResult } = render(
<DocumentContext.Provider value={context as DocumentContextType}>
{children}
</DocumentContext.Provider>,
);
return {
...otherResult,
rerender: (
nextChildren: React.ReactNode,
nextContext: Partial<DocumentContextType> = context,
) =>
rerender(
<DocumentContext.Provider value={nextContext as DocumentContextType}>
{nextChildren}
</DocumentContext.Provider>,
),
};
}
describe('Outline', () => {
// Loaded PDF file
let pdf: PDFDocumentProxy;
let pdf2: PDFDocumentProxy;
// Object with basic loaded outline information that shall match after successful loading
let desiredLoadedOutline: PDFOutline;
let desiredLoadedOutline2: PDFOutline;
beforeAll(async () => {
pdf = await pdfjs.getDocument({ data: pdfFile.arrayBuffer }).promise;
pdf2 = await pdfjs.getDocument({ data: pdfFile2.arrayBuffer }).promise;
desiredLoadedOutline = await pdf.getOutline();
desiredLoadedOutline2 = await pdf2.getOutline();
});
describe('loading', () => {
it('loads an outline and calls onLoadSuccess callback properly when placed inside Document', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
renderWithContext(<Outline onLoadSuccess={onLoadSuccess} />, { pdf });
expect.assertions(1);
await expect(onLoadSuccessPromise).resolves.toMatchObject([desiredLoadedOutline]);
});
it('loads an outline and calls onLoadSuccess callback properly when pdf prop is passed', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
render(<Outline onLoadSuccess={onLoadSuccess} pdf={pdf} />);
expect.assertions(1);
await expect(onLoadSuccessPromise).resolves.toMatchObject([desiredLoadedOutline]);
});
it('calls onLoadError when failed to load an outline', async () => {
const { func: onLoadError, promise: onLoadErrorPromise } = makeAsyncCallback();
muteConsole();
renderWithContext(<Outline onLoadError={onLoadError} />, { pdf: failingPdf });
expect.assertions(1);
await expect(onLoadErrorPromise).resolves.toMatchObject([expect.any(Error)]);
restoreConsole();
});
it('replaces an outline properly when pdf is changed', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
const { rerender } = renderWithContext(<Outline onLoadSuccess={onLoadSuccess} />, { pdf });
expect.assertions(2);
await expect(onLoadSuccessPromise).resolves.toMatchObject([desiredLoadedOutline]);
const { func: onLoadSuccess2, promise: onLoadSuccessPromise2 } = makeAsyncCallback();
rerender(<Outline onLoadSuccess={onLoadSuccess2} />, { pdf: pdf2 });
// It would have been .toMatchObject if not for the fact _pdf2.pdf has no outline
await expect(onLoadSuccessPromise2).resolves.toMatchObject([desiredLoadedOutline2]);
});
it('throws an error when placed outside Document without pdf prop passed', () => {
muteConsole();
expect(() => render(<Outline />)).toThrow();
restoreConsole();
});
});
describe('rendering', () => {
it('applies className to its wrapper when given a string', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
const className = 'testClassName';
const { container } = renderWithContext(
<Outline className={className} onLoadSuccess={onLoadSuccess} />,
{ pdf },
);
expect.assertions(1);
await onLoadSuccessPromise;
const wrapper = container.querySelector('.react-pdf__Outline');
expect(wrapper).toHaveClass(className);
});
it('passes container element to inputRef properly', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
const inputRef = createRef<HTMLDivElement>();
renderWithContext(<Outline inputRef={inputRef} onLoadSuccess={onLoadSuccess} />, { pdf });
expect.assertions(1);
await onLoadSuccessPromise;
expect(inputRef.current).toBeInstanceOf(HTMLDivElement);
});
it('renders OutlineItem components properly', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
renderWithContext(<Outline onLoadSuccess={onLoadSuccess} />, { pdf });
expect.assertions(1);
await onLoadSuccessPromise;
const items = screen.getAllByRole('listitem');
expect(items).toHaveLength(5);
});
});
});

View File

@@ -0,0 +1,221 @@
/**
* @fileoverview Rule to flag use of console object
* @author Nicholas C. Zakas
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
type: "suggestion",
defaultOptions: [{}],
docs: {
description: "Disallow the use of `console`",
recommended: false,
url: "https://eslint.org/docs/latest/rules/no-console",
},
schema: [
{
type: "object",
properties: {
allow: {
type: "array",
items: {
type: "string",
},
minItems: 1,
uniqueItems: true,
},
},
additionalProperties: false,
},
],
hasSuggestions: true,
messages: {
unexpected: "Unexpected console statement.",
limited:
"Unexpected console statement. Only these console methods are allowed: {{ allowed }}.",
removeConsole: "Remove the console.{{ propertyName }}().",
removeMethodCall: "Remove the console method call.",
},
},
create(context) {
const [{ allow: allowed = [] }] = context.options;
const sourceCode = context.sourceCode;
/**
* Checks whether the given reference is 'console' or not.
* @param {eslint-scope.Reference} reference The reference to check.
* @returns {boolean} `true` if the reference is 'console'.
*/
function isConsole(reference) {
const id = reference.identifier;
return id && id.name === "console";
}
/**
* Checks whether the property name of the given MemberExpression node
* is allowed by options or not.
* @param {ASTNode} node The MemberExpression node to check.
* @returns {boolean} `true` if the property name of the node is allowed.
*/
function isAllowed(node) {
const propertyName = astUtils.getStaticPropertyName(node);
return propertyName && allowed.includes(propertyName);
}
/**
* Checks whether the given reference is a member access which is not
* allowed by options or not.
* @param {eslint-scope.Reference} reference The reference to check.
* @returns {boolean} `true` if the reference is a member access which
* is not allowed by options.
*/
function isMemberAccessExceptAllowed(reference) {
const node = reference.identifier;
const parent = node.parent;
return (
parent.type === "MemberExpression" &&
parent.object === node &&
!isAllowed(parent)
);
}
/**
* Checks if removing the ExpressionStatement node will cause ASI to
* break.
* eg.
* foo()
* console.log();
* [1, 2, 3].forEach(a => doSomething(a))
*
* Removing the console.log(); statement should leave two statements, but
* here the two statements will become one because [ causes continuation after
* foo().
* @param {ASTNode} node The ExpressionStatement node to check.
* @returns {boolean} `true` if ASI will break after removing the ExpressionStatement
* node.
*/
function maybeAsiHazard(node) {
const SAFE_TOKENS_BEFORE = /^[:;{]$/u; // One of :;{
const UNSAFE_CHARS_AFTER = /^[-[(/+`]/u; // One of [(/+-`
const tokenBefore = sourceCode.getTokenBefore(node);
const tokenAfter = sourceCode.getTokenAfter(node);
return (
Boolean(tokenAfter) &&
UNSAFE_CHARS_AFTER.test(tokenAfter.value) &&
tokenAfter.value !== "++" &&
tokenAfter.value !== "--" &&
Boolean(tokenBefore) &&
!SAFE_TOKENS_BEFORE.test(tokenBefore.value)
);
}
/**
* Checks if the MemberExpression node's parent.parent.parent is a
* Program, BlockStatement, StaticBlock, or SwitchCase node. This check
* is necessary to avoid providing a suggestion that might cause a syntax error.
*
* eg. if (a) console.log(b), removing console.log() here will lead to a
* syntax error.
* if (a) { console.log(b) }, removing console.log() here is acceptable.
*
* Additionally, it checks if the callee of the CallExpression node is
* the node itself.
*
* eg. foo(console.log), cannot provide a suggestion here.
* @param {ASTNode} node The MemberExpression node to check.
* @returns {boolean} `true` if a suggestion can be provided for a node.
*/
function canProvideSuggestions(node) {
return (
node.parent.type === "CallExpression" &&
node.parent.callee === node &&
node.parent.parent.type === "ExpressionStatement" &&
astUtils.STATEMENT_LIST_PARENTS.has(
node.parent.parent.parent.type,
) &&
!maybeAsiHazard(node.parent.parent)
);
}
/**
* Reports the given reference as a violation.
* @param {eslint-scope.Reference} reference The reference to report.
* @returns {void}
*/
function report(reference) {
const node = reference.identifier.parent;
const suggest = [];
if (canProvideSuggestions(node)) {
const suggestion = {
fix(fixer) {
return fixer.remove(node.parent.parent);
},
};
if (node.computed) {
suggestion.messageId = "removeMethodCall";
} else {
suggestion.messageId = "removeConsole";
suggestion.data = { propertyName: node.property.name };
}
suggest.push(suggestion);
}
context.report({
node,
loc: node.loc,
messageId: allowed.length ? "limited" : "unexpected",
data: { allowed: allowed.join(", ") },
suggest,
});
}
return {
"Program:exit"(node) {
const scope = sourceCode.getScope(node);
const consoleVar = astUtils.getVariableByName(scope, "console");
const shadowed = consoleVar && consoleVar.defs.length > 0;
/*
* 'scope.through' includes all references to undefined
* variables. If the variable 'console' is not defined, it uses
* 'scope.through'.
*/
const references = consoleVar
? consoleVar.references
: scope.through.filter(isConsole);
if (!shadowed) {
references
.filter(isMemberAccessExceptAllowed)
.forEach(report);
}
},
};
},
};

View File

@@ -0,0 +1,186 @@
/**
* @fileoverview Rule to disallow assignments where both sides are exactly the same
* @author Toru Nagashima
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const SPACES = /\s+/gu;
/**
* Traverses 2 Pattern nodes in parallel, then reports self-assignments.
* @param {ASTNode|null} left A left node to traverse. This is a Pattern or
* a Property.
* @param {ASTNode|null} right A right node to traverse. This is a Pattern or
* a Property.
* @param {boolean} props The flag to check member expressions as well.
* @param {Function} report A callback function to report.
* @returns {void}
*/
function eachSelfAssignment(left, right, props, report) {
if (!left || !right) {
// do nothing
} else if (
left.type === "Identifier" &&
right.type === "Identifier" &&
left.name === right.name
) {
report(right);
} else if (
left.type === "ArrayPattern" &&
right.type === "ArrayExpression"
) {
const end = Math.min(left.elements.length, right.elements.length);
for (let i = 0; i < end; ++i) {
const leftElement = left.elements[i];
const rightElement = right.elements[i];
// Avoid cases such as [...a] = [...a, 1]
if (
leftElement &&
leftElement.type === "RestElement" &&
i < right.elements.length - 1
) {
break;
}
eachSelfAssignment(leftElement, rightElement, props, report);
// After a spread element, those indices are unknown.
if (rightElement && rightElement.type === "SpreadElement") {
break;
}
}
} else if (left.type === "RestElement" && right.type === "SpreadElement") {
eachSelfAssignment(left.argument, right.argument, props, report);
} else if (
left.type === "ObjectPattern" &&
right.type === "ObjectExpression" &&
right.properties.length >= 1
) {
/*
* Gets the index of the last spread property.
* It's possible to overwrite properties followed by it.
*/
let startJ = 0;
for (let i = right.properties.length - 1; i >= 0; --i) {
const propType = right.properties[i].type;
if (
propType === "SpreadElement" ||
propType === "ExperimentalSpreadProperty"
) {
startJ = i + 1;
break;
}
}
for (let i = 0; i < left.properties.length; ++i) {
for (let j = startJ; j < right.properties.length; ++j) {
eachSelfAssignment(
left.properties[i],
right.properties[j],
props,
report,
);
}
}
} else if (
left.type === "Property" &&
right.type === "Property" &&
right.kind === "init" &&
!right.method
) {
const leftName = astUtils.getStaticPropertyName(left);
if (
leftName !== null &&
leftName === astUtils.getStaticPropertyName(right)
) {
eachSelfAssignment(left.value, right.value, props, report);
}
} else if (
props &&
astUtils.skipChainExpression(left).type === "MemberExpression" &&
astUtils.skipChainExpression(right).type === "MemberExpression" &&
astUtils.isSameReference(left, right)
) {
report(right);
}
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
type: "problem",
defaultOptions: [{ props: true }],
docs: {
description:
"Disallow assignments where both sides are exactly the same",
recommended: true,
url: "https://eslint.org/docs/latest/rules/no-self-assign",
},
schema: [
{
type: "object",
properties: {
props: {
type: "boolean",
},
},
additionalProperties: false,
},
],
messages: {
selfAssignment: "'{{name}}' is assigned to itself.",
},
},
create(context) {
const sourceCode = context.sourceCode;
const [{ props }] = context.options;
/**
* Reports a given node as self assignments.
* @param {ASTNode} node A node to report. This is an Identifier node.
* @returns {void}
*/
function report(node) {
context.report({
node,
messageId: "selfAssignment",
data: {
name: sourceCode.getText(node).replace(SPACES, ""),
},
});
}
return {
AssignmentExpression(node) {
if (["=", "&&=", "||=", "??="].includes(node.operator)) {
eachSelfAssignment(node.left, node.right, props, report);
}
},
};
},
};