加入了node_modules

添加了新的功能项
This commit is contained in:
zyb
2025-05-13 21:23:41 +08:00
parent 8d53374568
commit 0c0b5d869c
3589 changed files with 893641 additions and 233 deletions

51
node_modules/execa/lib/transform/encoding-transform.js generated vendored Normal file
View File

@@ -0,0 +1,51 @@
import {Buffer} from 'node:buffer';
import {StringDecoder} from 'node:string_decoder';
import {isUint8Array, bufferToUint8Array} from '../utils/uint-array.js';
/*
When using binary encodings, add an internal generator that converts chunks from `Buffer` to `string` or `Uint8Array`.
Chunks might be Buffer, Uint8Array or strings since:
- `subprocess.stdout|stderr` emits Buffers
- `subprocess.stdin.write()` accepts Buffer, Uint8Array or string
- Previous generators might return Uint8Array or string
However, those are converted to Buffer:
- on writes: `Duplex.writable` `decodeStrings: true` default option
- on reads: `Duplex.readable` `readableEncoding: null` default option
*/
export const getEncodingTransformGenerator = (binary, encoding, skipped) => {
if (skipped) {
return;
}
if (binary) {
return {transform: encodingUint8ArrayGenerator.bind(undefined, new TextEncoder())};
}
const stringDecoder = new StringDecoder(encoding);
return {
transform: encodingStringGenerator.bind(undefined, stringDecoder),
final: encodingStringFinal.bind(undefined, stringDecoder),
};
};
const encodingUint8ArrayGenerator = function * (textEncoder, chunk) {
if (Buffer.isBuffer(chunk)) {
yield bufferToUint8Array(chunk);
} else if (typeof chunk === 'string') {
yield textEncoder.encode(chunk);
} else {
yield chunk;
}
};
const encodingStringGenerator = function * (stringDecoder, chunk) {
yield isUint8Array(chunk) ? stringDecoder.write(chunk) : chunk;
};
const encodingStringFinal = function * (stringDecoder) {
const lastChunk = stringDecoder.end();
if (lastChunk !== '') {
yield lastChunk;
}
};

107
node_modules/execa/lib/transform/generator.js generated vendored Normal file
View File

@@ -0,0 +1,107 @@
import {Transform, getDefaultHighWaterMark} from 'node:stream';
import {isAsyncGenerator} from '../stdio/type.js';
import {getSplitLinesGenerator, getAppendNewlineGenerator} from './split.js';
import {getValidateTransformInput, getValidateTransformReturn} from './validate.js';
import {getEncodingTransformGenerator} from './encoding-transform.js';
import {
pushChunks,
transformChunk,
finalChunks,
destroyTransform,
} from './run-async.js';
import {
pushChunksSync,
transformChunkSync,
finalChunksSync,
runTransformSync,
} from './run-sync.js';
/*
Generators can be used to transform/filter standard streams.
Generators have a simple syntax, yet allows all of the following:
- Sharing `state` between chunks
- Flushing logic, by using a `final` function
- Asynchronous logic
- Emitting multiple chunks from a single source chunk, even if spaced in time, by using multiple `yield`
- Filtering, by using no `yield`
Therefore, there is no need to allow Node.js or web transform streams.
The `highWaterMark` is kept as the default value, since this is what `subprocess.std*` uses.
Chunks are currently processed serially. We could add a `concurrency` option to parallelize in the future.
Transform an array of generator functions into a `Transform` stream.
`Duplex.from(generator)` cannot be used because it does not allow setting the `objectMode` and `highWaterMark`.
*/
export const generatorToStream = ({
value,
value: {transform, final, writableObjectMode, readableObjectMode},
optionName,
}, {encoding}) => {
const state = {};
const generators = addInternalGenerators(value, encoding, optionName);
const transformAsync = isAsyncGenerator(transform);
const finalAsync = isAsyncGenerator(final);
const transformMethod = transformAsync
? pushChunks.bind(undefined, transformChunk, state)
: pushChunksSync.bind(undefined, transformChunkSync);
const finalMethod = transformAsync || finalAsync
? pushChunks.bind(undefined, finalChunks, state)
: pushChunksSync.bind(undefined, finalChunksSync);
const destroyMethod = transformAsync || finalAsync
? destroyTransform.bind(undefined, state)
: undefined;
const stream = new Transform({
writableObjectMode,
writableHighWaterMark: getDefaultHighWaterMark(writableObjectMode),
readableObjectMode,
readableHighWaterMark: getDefaultHighWaterMark(readableObjectMode),
transform(chunk, encoding, done) {
transformMethod([chunk, generators, 0], this, done);
},
flush(done) {
finalMethod([generators], this, done);
},
destroy: destroyMethod,
});
return {stream};
};
// Applies transform generators in sync mode
export const runGeneratorsSync = (chunks, stdioItems, encoding, isInput) => {
const generators = stdioItems.filter(({type}) => type === 'generator');
const reversedGenerators = isInput ? generators.reverse() : generators;
for (const {value, optionName} of reversedGenerators) {
const generators = addInternalGenerators(value, encoding, optionName);
chunks = runTransformSync(generators, chunks);
}
return chunks;
};
// Generators used internally to convert the chunk type, validate it, and split into lines
const addInternalGenerators = (
{transform, final, binary, writableObjectMode, readableObjectMode, preserveNewlines},
encoding,
optionName,
) => {
const state = {};
return [
{transform: getValidateTransformInput(writableObjectMode, optionName)},
getEncodingTransformGenerator(binary, encoding, writableObjectMode),
getSplitLinesGenerator(binary, preserveNewlines, writableObjectMode, state),
{transform, final},
{transform: getValidateTransformReturn(readableObjectMode, optionName)},
getAppendNewlineGenerator({
binary,
preserveNewlines,
readableObjectMode,
state,
}),
].filter(Boolean);
};

111
node_modules/execa/lib/transform/normalize.js generated vendored Normal file
View File

@@ -0,0 +1,111 @@
import isPlainObj from 'is-plain-obj';
import {BINARY_ENCODINGS} from '../arguments/encoding-option.js';
import {TRANSFORM_TYPES} from '../stdio/type.js';
import {getTransformObjectModes} from './object-mode.js';
// Transforms generators/duplex/TransformStream can have multiple shapes.
// This normalizes it and applies default values.
export const normalizeTransforms = (stdioItems, optionName, direction, options) => [
...stdioItems.filter(({type}) => !TRANSFORM_TYPES.has(type)),
...getTransforms(stdioItems, optionName, direction, options),
];
const getTransforms = (stdioItems, optionName, direction, {encoding}) => {
const transforms = stdioItems.filter(({type}) => TRANSFORM_TYPES.has(type));
const newTransforms = Array.from({length: transforms.length});
for (const [index, stdioItem] of Object.entries(transforms)) {
newTransforms[index] = normalizeTransform({
stdioItem,
index: Number(index),
newTransforms,
optionName,
direction,
encoding,
});
}
return sortTransforms(newTransforms, direction);
};
const normalizeTransform = ({stdioItem, stdioItem: {type}, index, newTransforms, optionName, direction, encoding}) => {
if (type === 'duplex') {
return normalizeDuplex({stdioItem, optionName});
}
if (type === 'webTransform') {
return normalizeTransformStream({
stdioItem,
index,
newTransforms,
direction,
});
}
return normalizeGenerator({
stdioItem,
index,
newTransforms,
direction,
encoding,
});
};
const normalizeDuplex = ({
stdioItem,
stdioItem: {
value: {
transform,
transform: {writableObjectMode, readableObjectMode},
objectMode = readableObjectMode,
},
},
optionName,
}) => {
if (objectMode && !readableObjectMode) {
throw new TypeError(`The \`${optionName}.objectMode\` option can only be \`true\` if \`new Duplex({objectMode: true})\` is used.`);
}
if (!objectMode && readableObjectMode) {
throw new TypeError(`The \`${optionName}.objectMode\` option cannot be \`false\` if \`new Duplex({objectMode: true})\` is used.`);
}
return {
...stdioItem,
value: {transform, writableObjectMode, readableObjectMode},
};
};
const normalizeTransformStream = ({stdioItem, stdioItem: {value}, index, newTransforms, direction}) => {
const {transform, objectMode} = isPlainObj(value) ? value : {transform: value};
const {writableObjectMode, readableObjectMode} = getTransformObjectModes(objectMode, index, newTransforms, direction);
return ({
...stdioItem,
value: {transform, writableObjectMode, readableObjectMode},
});
};
const normalizeGenerator = ({stdioItem, stdioItem: {value}, index, newTransforms, direction, encoding}) => {
const {
transform,
final,
binary: binaryOption = false,
preserveNewlines = false,
objectMode,
} = isPlainObj(value) ? value : {transform: value};
const binary = binaryOption || BINARY_ENCODINGS.has(encoding);
const {writableObjectMode, readableObjectMode} = getTransformObjectModes(objectMode, index, newTransforms, direction);
return {
...stdioItem,
value: {
transform,
final,
binary,
preserveNewlines,
writableObjectMode,
readableObjectMode,
},
};
};
const sortTransforms = (newTransforms, direction) => direction === 'input' ? newTransforms.reverse() : newTransforms;

41
node_modules/execa/lib/transform/object-mode.js generated vendored Normal file
View File

@@ -0,0 +1,41 @@
import {TRANSFORM_TYPES} from '../stdio/type.js';
/*
Retrieve the `objectMode`s of a single transform.
`objectMode` determines the return value's type, i.e. the `readableObjectMode`.
The chunk argument's type is based on the previous generator's return value, i.e. the `writableObjectMode` is based on the previous `readableObjectMode`.
The last input's generator is read by `subprocess.stdin` which:
- should not be in `objectMode` for performance reasons.
- can only be strings, Buffers and Uint8Arrays.
Therefore its `readableObjectMode` must be `false`.
The same applies to the first output's generator's `writableObjectMode`.
*/
export const getTransformObjectModes = (objectMode, index, newTransforms, direction) => direction === 'output'
? getOutputObjectModes(objectMode, index, newTransforms)
: getInputObjectModes(objectMode, index, newTransforms);
const getOutputObjectModes = (objectMode, index, newTransforms) => {
const writableObjectMode = index !== 0 && newTransforms[index - 1].value.readableObjectMode;
const readableObjectMode = objectMode ?? writableObjectMode;
return {writableObjectMode, readableObjectMode};
};
const getInputObjectModes = (objectMode, index, newTransforms) => {
const writableObjectMode = index === 0
? objectMode === true
: newTransforms[index - 1].value.readableObjectMode;
const readableObjectMode = index !== newTransforms.length - 1 && (objectMode ?? writableObjectMode);
return {writableObjectMode, readableObjectMode};
};
// Retrieve the `objectMode` of a file descriptor, e.g. `stdout` or `stderr`
export const getFdObjectMode = (stdioItems, direction) => {
const lastTransform = stdioItems.findLast(({type}) => TRANSFORM_TYPES.has(type));
if (lastTransform === undefined) {
return false;
}
return direction === 'input'
? lastTransform.value.writableObjectMode
: lastTransform.value.readableObjectMode;
};

60
node_modules/execa/lib/transform/run-async.js generated vendored Normal file
View File

@@ -0,0 +1,60 @@
import {callbackify} from 'node:util';
// Applies a series of generator functions asynchronously
export const pushChunks = callbackify(async (getChunks, state, getChunksArguments, transformStream) => {
state.currentIterable = getChunks(...getChunksArguments);
try {
for await (const chunk of state.currentIterable) {
transformStream.push(chunk);
}
} finally {
delete state.currentIterable;
}
});
// For each new chunk, apply each `transform()` method
export const transformChunk = async function * (chunk, generators, index) {
if (index === generators.length) {
yield chunk;
return;
}
const {transform = identityGenerator} = generators[index];
for await (const transformedChunk of transform(chunk)) {
yield * transformChunk(transformedChunk, generators, index + 1);
}
};
// At the end, apply each `final()` method, followed by the `transform()` method of the next transforms
export const finalChunks = async function * (generators) {
for (const [index, {final}] of Object.entries(generators)) {
yield * generatorFinalChunks(final, Number(index), generators);
}
};
const generatorFinalChunks = async function * (final, index, generators) {
if (final === undefined) {
return;
}
for await (const finalChunk of final()) {
yield * transformChunk(finalChunk, generators, index + 1);
}
};
// Cancel any ongoing async generator when the Transform is destroyed, e.g. when the subprocess errors
export const destroyTransform = callbackify(async ({currentIterable}, error) => {
if (currentIterable !== undefined) {
await (error ? currentIterable.throw(error) : currentIterable.return());
return;
}
if (error) {
throw error;
}
});
const identityGenerator = function * (chunk) {
yield chunk;
};

50
node_modules/execa/lib/transform/run-sync.js generated vendored Normal file
View File

@@ -0,0 +1,50 @@
// Duplicate the code from `run-async.js` but as synchronous functions
export const pushChunksSync = (getChunksSync, getChunksArguments, transformStream, done) => {
try {
for (const chunk of getChunksSync(...getChunksArguments)) {
transformStream.push(chunk);
}
done();
} catch (error) {
done(error);
}
};
// Run synchronous generators with `execaSync()`
export const runTransformSync = (generators, chunks) => [
...chunks.flatMap(chunk => [...transformChunkSync(chunk, generators, 0)]),
...finalChunksSync(generators),
];
export const transformChunkSync = function * (chunk, generators, index) {
if (index === generators.length) {
yield chunk;
return;
}
const {transform = identityGenerator} = generators[index];
for (const transformedChunk of transform(chunk)) {
yield * transformChunkSync(transformedChunk, generators, index + 1);
}
};
export const finalChunksSync = function * (generators) {
for (const [index, {final}] of Object.entries(generators)) {
yield * generatorFinalChunksSync(final, Number(index), generators);
}
};
const generatorFinalChunksSync = function * (final, index, generators) {
if (final === undefined) {
return;
}
for (const finalChunk of final()) {
yield * transformChunkSync(finalChunk, generators, index + 1);
}
};
const identityGenerator = function * (chunk) {
yield chunk;
};

110
node_modules/execa/lib/transform/split.js generated vendored Normal file
View File

@@ -0,0 +1,110 @@
// Split chunks line-wise for generators passed to the `std*` options
export const getSplitLinesGenerator = (binary, preserveNewlines, skipped, state) => binary || skipped
? undefined
: initializeSplitLines(preserveNewlines, state);
// Same but for synchronous methods
export const splitLinesSync = (chunk, preserveNewlines, objectMode) => objectMode
? chunk.flatMap(item => splitLinesItemSync(item, preserveNewlines))
: splitLinesItemSync(chunk, preserveNewlines);
const splitLinesItemSync = (chunk, preserveNewlines) => {
const {transform, final} = initializeSplitLines(preserveNewlines, {});
return [...transform(chunk), ...final()];
};
const initializeSplitLines = (preserveNewlines, state) => {
state.previousChunks = '';
return {
transform: splitGenerator.bind(undefined, state, preserveNewlines),
final: linesFinal.bind(undefined, state),
};
};
// This imperative logic is much faster than using `String.split()` and uses very low memory.
const splitGenerator = function * (state, preserveNewlines, chunk) {
if (typeof chunk !== 'string') {
yield chunk;
return;
}
let {previousChunks} = state;
let start = -1;
for (let end = 0; end < chunk.length; end += 1) {
if (chunk[end] === '\n') {
const newlineLength = getNewlineLength(chunk, end, preserveNewlines, state);
let line = chunk.slice(start + 1, end + 1 - newlineLength);
if (previousChunks.length > 0) {
line = concatString(previousChunks, line);
previousChunks = '';
}
yield line;
start = end;
}
}
if (start !== chunk.length - 1) {
previousChunks = concatString(previousChunks, chunk.slice(start + 1));
}
state.previousChunks = previousChunks;
};
const getNewlineLength = (chunk, end, preserveNewlines, state) => {
if (preserveNewlines) {
return 0;
}
state.isWindowsNewline = end !== 0 && chunk[end - 1] === '\r';
return state.isWindowsNewline ? 2 : 1;
};
const linesFinal = function * ({previousChunks}) {
if (previousChunks.length > 0) {
yield previousChunks;
}
};
// Unless `preserveNewlines: true` is used, we strip the newline of each line.
// This re-adds them after the user `transform` code has run.
export const getAppendNewlineGenerator = ({binary, preserveNewlines, readableObjectMode, state}) => binary || preserveNewlines || readableObjectMode
? undefined
: {transform: appendNewlineGenerator.bind(undefined, state)};
const appendNewlineGenerator = function * ({isWindowsNewline = false}, chunk) {
const {unixNewline, windowsNewline, LF, concatBytes} = typeof chunk === 'string' ? linesStringInfo : linesUint8ArrayInfo;
if (chunk.at(-1) === LF) {
yield chunk;
return;
}
const newline = isWindowsNewline ? windowsNewline : unixNewline;
yield concatBytes(chunk, newline);
};
const concatString = (firstChunk, secondChunk) => `${firstChunk}${secondChunk}`;
const linesStringInfo = {
windowsNewline: '\r\n',
unixNewline: '\n',
LF: '\n',
concatBytes: concatString,
};
const concatUint8Array = (firstChunk, secondChunk) => {
const chunk = new Uint8Array(firstChunk.length + secondChunk.length);
chunk.set(firstChunk, 0);
chunk.set(secondChunk, firstChunk.length);
return chunk;
};
const linesUint8ArrayInfo = {
windowsNewline: new Uint8Array([0x0D, 0x0A]),
unixNewline: new Uint8Array([0x0A]),
LF: 0x0A,
concatBytes: concatUint8Array,
};

43
node_modules/execa/lib/transform/validate.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
import {Buffer} from 'node:buffer';
import {isUint8Array} from '../utils/uint-array.js';
// Validate the type of chunk argument passed to transform generators
export const getValidateTransformInput = (writableObjectMode, optionName) => writableObjectMode
? undefined
: validateStringTransformInput.bind(undefined, optionName);
const validateStringTransformInput = function * (optionName, chunk) {
if (typeof chunk !== 'string' && !isUint8Array(chunk) && !Buffer.isBuffer(chunk)) {
throw new TypeError(`The \`${optionName}\` option's transform must use "objectMode: true" to receive as input: ${typeof chunk}.`);
}
yield chunk;
};
// Validate the type of the value returned by transform generators
export const getValidateTransformReturn = (readableObjectMode, optionName) => readableObjectMode
? validateObjectTransformReturn.bind(undefined, optionName)
: validateStringTransformReturn.bind(undefined, optionName);
const validateObjectTransformReturn = function * (optionName, chunk) {
validateEmptyReturn(optionName, chunk);
yield chunk;
};
const validateStringTransformReturn = function * (optionName, chunk) {
validateEmptyReturn(optionName, chunk);
if (typeof chunk !== 'string' && !isUint8Array(chunk)) {
throw new TypeError(`The \`${optionName}\` option's function must yield a string or an Uint8Array, not ${typeof chunk}.`);
}
yield chunk;
};
const validateEmptyReturn = (optionName, chunk) => {
if (chunk === null || chunk === undefined) {
throw new TypeError(`The \`${optionName}\` option's function must not call \`yield ${chunk}\`.
Instead, \`yield\` should either be called with a value, or not be called at all. For example:
if (condition) { yield value; }`);
}
};