Update test framework: fix run_tests.py to support all test files, add auto-import-check for test files

This commit is contained in:
qiaoxinjiu
2026-05-09 15:11:30 +08:00
parent eb053a347f
commit eaba8328da
21739 changed files with 2236758 additions and 719 deletions

View File

@@ -0,0 +1,118 @@
'use strict'
const { Parser } = require('acorn')
const { importAttributesOrAssertions } = require('acorn-import-attributes')
const acornOpts = {
ecmaVersion: 'latest',
sourceType: 'module'
}
const parser = Parser.extend(importAttributesOrAssertions)
function warn (txt) {
process.emitWarning(txt, 'get-esm-exports')
}
/**
* Utilizes an AST parser to interpret ESM source code and build a list of
* exported identifiers. In the baseline case, the list of identifiers will be
* the simple identifier names as written in the source code of the module.
* However, there is a special case:
*
* When an `export * from './foo.js'` line is encountered it is rewritten
* as `* from ./foo.js`. This allows the interpreting code to recognize a
* transitive export and recursively parse the indicated module. The returned
* identifier list will have "* from ./foo.js" as an item.
*
* @param {object} params
* @param {string} params.moduleSource The source code of the module to parse
* and interpret.
*
* @returns {Set<string>} The identifiers exported by the module along with any
* custom directives.
*/
function getEsmExports (moduleSource) {
const exportedNames = new Set()
const tree = parser.parse(moduleSource, acornOpts)
for (const node of tree.body) {
if (!node.type.startsWith('Export')) continue
switch (node.type) {
case 'ExportNamedDeclaration':
if (node.declaration) {
parseDeclaration(node, exportedNames)
} else {
parseSpecifiers(node, exportedNames)
}
break
case 'ExportDefaultDeclaration': {
exportedNames.add('default')
break
}
case 'ExportAllDeclaration':
if (node.exported) {
exportedNames.add(node.exported.name)
} else {
exportedNames.add(`* from ${node.source.value}`)
}
break
default:
warn('unrecognized export type: ' + node.type)
}
}
return exportedNames
}
function parseDeclaration (node, exportedNames) {
switch (node.declaration.type) {
case 'FunctionDeclaration':
exportedNames.add(node.declaration.id.name)
break
case 'VariableDeclaration':
for (const varDecl of node.declaration.declarations) {
parseVariableDeclaration(varDecl, exportedNames)
}
break
case 'ClassDeclaration':
exportedNames.add(node.declaration.id.name)
break
default:
warn('unknown declaration type: ' + node.delcaration.type)
}
}
function parseVariableDeclaration (node, exportedNames) {
switch (node.id.type) {
case 'Identifier':
exportedNames.add(node.id.name)
break
case 'ObjectPattern':
for (const prop of node.id.properties) {
exportedNames.add(prop.value.name)
}
break
case 'ArrayPattern':
for (const elem of node.id.elements) {
exportedNames.add(elem.name)
}
break
default:
warn('unknown variable declaration type: ' + node.id.type)
}
}
function parseSpecifiers (node, exportedNames) {
for (const specifier of node.specifiers) {
if (specifier.exported.type === 'Identifier') {
exportedNames.add(specifier.exported.name)
} else if (specifier.exported.type === 'Literal') {
exportedNames.add(specifier.exported.value)
} else {
warn('unrecognized specifier type: ' + specifier.exported.type)
}
}
}
module.exports = getEsmExports

192
node_modules/import-in-the-middle/lib/get-exports.js generated vendored Normal file
View File

@@ -0,0 +1,192 @@
'use strict'
const getEsmExports = require('./get-esm-exports.js')
const { parse: parseCjs } = require('cjs-module-lexer')
const { readFileSync, existsSync } = require('fs')
const { builtinModules } = require('module')
const { fileURLToPath, pathToFileURL } = require('url')
const { dirname, join } = require('path')
function addDefault (arr) {
return new Set(['default', ...arr])
}
// Cached exports for Node built-in modules
const BUILT_INS = new Map()
function getExportsForNodeBuiltIn (name) {
let exports = BUILT_INS.get()
if (!exports) {
exports = new Set(addDefault(Object.keys(require(name))))
BUILT_INS.set(name, exports)
}
return exports
}
const urlsBeingProcessed = new Set() // Guard against circular imports.
/**
* This function looks for the package.json which contains the specifier trying to resolve.
* Once the package.json file has been found, we extract the file path from the specifier
* @param {string} specifier The specifier that is being search for inside the imports object
* @param {URL|string} fromUrl The url from which the search starts from
* @returns array with url and resolvedExport
*/
function resolvePackageImports (specifier, fromUrl) {
try {
const fromPath = fileURLToPath(fromUrl)
let currentDir = dirname(fromPath)
// search for package.json file which has the real url to export
while (currentDir !== dirname(currentDir)) {
const packageJsonPath = join(currentDir, 'package.json')
if (existsSync(packageJsonPath)) {
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
if (packageJson.imports && packageJson.imports[specifier]) {
const imports = packageJson.imports[specifier]
// Look for path inside packageJson
let resolvedExport
if (imports && typeof imports === 'object') {
const requireExport = imports.require
const importExport = imports.import
// look for the possibility of require and import which is standard for CJS/ESM
if (requireExport || importExport) {
// trying to resolve based on order of importance
resolvedExport = requireExport.node || requireExport.default || importExport.node || importExport.default
} else if (imports.node || imports.default) {
resolvedExport = imports.node || imports.default
}
} else if (typeof imports === 'string') {
resolvedExport = imports
}
if (resolvedExport) {
const url = resolvedExport.startsWith('.')
? pathToFileURL(join(currentDir, resolvedExport))
: fromUrl
return [url, resolvedExport]
}
}
// return if we find a package.json but did not find an import
return null
}
currentDir = dirname(currentDir)
}
} catch (cause) {
throw Error(`Failed to find export: ${specifier}`, { cause })
}
return null
}
async function getCjsExports (url, context, parentLoad, source) {
if (urlsBeingProcessed.has(url)) {
return []
}
urlsBeingProcessed.add(url)
try {
const result = parseCjs(source)
const full = addDefault(result.exports)
await Promise.all(result.reexports.map(async re => {
if (re.startsWith('node:') || builtinModules.includes(re)) {
for (const each of getExportsForNodeBuiltIn(re)) {
full.add(each)
}
} else {
if (re === '.') {
re = './'
}
// Entries in the import field should always start with #
if (re.startsWith('#')) {
const resolved = resolvePackageImports(re, url)
if (!resolved) return
[url, re] = resolved
}
const newUrl = pathToFileURL(require.resolve(re, { paths: [dirname(fileURLToPath(url))] })).href
if (newUrl.endsWith('.node') || newUrl.endsWith('.json')) {
return
}
for (const each of await getExports(newUrl, context, parentLoad)) {
full.add(each)
}
}
}))
return full
} finally {
urlsBeingProcessed.delete(url)
}
}
/**
* Inspects a module for its type (commonjs or module), attempts to get the
* source code for said module from the loader API, and parses the result
* for the entities exported from that module.
*
* @param {string} url A file URL string pointing to the module that
* we should get the exports of.
* @param {object} context Context object as provided by the `load`
* hook from the loaders API.
* @param {Function} parentLoad Next hook function in the loaders API
* hook chain.
*
* @returns {Promise<Set<string>>} An array of identifiers exported by the module.
* Please see {@link getEsmExports} for caveats on special identifiers that may
* be included in the result set.
*/
async function getExports (url, context, parentLoad) {
// `parentLoad` gives us the possibility of getting the source
// from an upstream loader. This doesn't always work though,
// so later on we fall back to reading it from disk.
const parentCtx = await parentLoad(url, context)
let source = parentCtx.source
const format = parentCtx.format
if (!source) {
if (format === 'builtin') {
// Builtins don't give us the source property, so we're stuck
// just requiring it to get the exports.
return getExportsForNodeBuiltIn(url)
}
// Sometimes source is retrieved by parentLoad, CommonJs isn't.
source = readFileSync(fileURLToPath(url), 'utf8')
}
try {
if (format === 'module') {
return getEsmExports(source)
}
if (format === 'commonjs') {
return await getCjsExports(url, context, parentLoad, source)
}
// At this point our `format` is either undefined or not known by us. Fall
// back to parsing as ESM/CJS.
const esmExports = getEsmExports(source)
if (!esmExports.length) {
// TODO(bengl) it's might be possible to get here if somehow the format
// isn't set at first and yet we have an ESM module with no exports.
// I couldn't construct an example that would do this, so maybe it's
// impossible?
return await getCjsExports(url, context, parentLoad, source)
}
} catch (cause) {
const err = new Error(`Failed to parse '${url}'`)
err.cause = cause
throw err
}
}
module.exports = getExports

61
node_modules/import-in-the-middle/lib/register.js generated vendored Normal file
View File

@@ -0,0 +1,61 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.
const importHooks = [] // TODO should this be a Set?
const setters = new WeakMap()
const getters = new WeakMap()
const specifiers = new Map()
const toHook = []
const proxyHandler = {
set (target, name, value) {
return setters.get(target)[name](value)
},
get (target, name) {
if (name === Symbol.toStringTag) {
return 'Module'
}
const getter = getters.get(target)[name]
if (typeof getter === 'function') {
return getter()
}
},
defineProperty (target, property, descriptor) {
if ((!('value' in descriptor))) {
throw new Error('Getters/setters are not supported for exports property descriptors.')
}
return setters.get(target)[property](descriptor.value)
}
}
function register (name, namespace, set, get, specifier) {
specifiers.set(name, specifier)
setters.set(namespace, set)
getters.set(namespace, get)
const proxy = new Proxy(namespace, proxyHandler)
importHooks.forEach(hook => hook(name, proxy))
toHook.push([name, proxy])
}
let experimentalPatchInternals = false
function getExperimentalPatchInternals () {
return experimentalPatchInternals
}
function setExperimentalPatchInternals (value) {
experimentalPatchInternals = value
}
exports.register = register
exports.importHooks = importHooks
exports.specifiers = specifiers
exports.toHook = toHook
exports.getExperimentalPatchInternals = getExperimentalPatchInternals
exports.setExperimentalPatchInternals = setExperimentalPatchInternals