mirror of
https://github.com/github/codeql-action.git
synced 2025-12-28 02:00:12 +08:00
142 lines
4.0 KiB
JavaScript
142 lines
4.0 KiB
JavaScript
'use strict';
|
|
|
|
const Encoder = require('./encoder');
|
|
const ObjectRecorder = require('./objectRecorder');
|
|
const {Buffer} = require('buffer');
|
|
|
|
/**
|
|
* Implement value sharing.
|
|
*
|
|
* @see {@link cbor.schmorp.de/value-sharing}
|
|
*/
|
|
class SharedValueEncoder extends Encoder {
|
|
constructor(opts) {
|
|
super(opts);
|
|
this.valueSharing = new ObjectRecorder();
|
|
}
|
|
|
|
/**
|
|
* @param {object} obj Object to encode.
|
|
* @param {import('./encoder').ObjectOptions} [opts] Options for encoding
|
|
* this object.
|
|
* @returns {boolean} True on success.
|
|
* @throws {Error} Loop detected.
|
|
* @ignore
|
|
*/
|
|
_pushObject(obj, opts) {
|
|
if (obj !== null) {
|
|
const shared = this.valueSharing.check(obj);
|
|
switch (shared) {
|
|
case ObjectRecorder.FIRST:
|
|
// Prefix with tag 28
|
|
this._pushTag(28);
|
|
break;
|
|
case ObjectRecorder.NEVER:
|
|
// Do nothing
|
|
break;
|
|
default:
|
|
return this._pushTag(29) && this._pushIntNum(shared);
|
|
}
|
|
}
|
|
return super._pushObject(obj, opts);
|
|
}
|
|
|
|
/**
|
|
* Between encoding runs, stop recording, and start outputing correct tags.
|
|
*/
|
|
stopRecording() {
|
|
this.valueSharing.stop();
|
|
}
|
|
|
|
/**
|
|
* Remove the existing recording and start over. Do this between encoding
|
|
* pairs.
|
|
*/
|
|
clearRecording() {
|
|
this.valueSharing.clear();
|
|
}
|
|
|
|
/**
|
|
* Encode one or more JavaScript objects, and return a Buffer containing the
|
|
* CBOR bytes.
|
|
*
|
|
* @param {...any} objs The objects to encode.
|
|
* @returns {Buffer} The encoded objects.
|
|
*/
|
|
static encode(...objs) {
|
|
const enc = new SharedValueEncoder();
|
|
// eslint-disable-next-line no-empty-function
|
|
enc.on('data', () => {}); // Sink all writes
|
|
|
|
for (const o of objs) {
|
|
enc.pushAny(o);
|
|
}
|
|
enc.stopRecording();
|
|
enc.removeAllListeners('data');
|
|
return enc._encodeAll(objs);
|
|
}
|
|
|
|
/**
|
|
* Encode one or more JavaScript objects canonically (slower!), and return
|
|
* a Buffer containing the CBOR bytes.
|
|
*
|
|
* @param {...any} _objs The objects to encode.
|
|
* @returns {Buffer} Never.
|
|
* @throws {Error} Always. This combination doesn't work at the moment.
|
|
*/
|
|
static encodeCanonical(..._objs) {
|
|
throw new Error('Cannot encode canonically in a SharedValueEncoder, which serializes objects multiple times.');
|
|
}
|
|
|
|
/**
|
|
* Encode one JavaScript object using the given options.
|
|
*
|
|
* @param {any} obj The object to encode.
|
|
* @param {import('./encoder').EncodingOptions} [options={}]
|
|
* Passed to the Encoder constructor.
|
|
* @returns {Buffer} The encoded objects.
|
|
* @static
|
|
*/
|
|
static encodeOne(obj, options) {
|
|
const enc = new SharedValueEncoder(options);
|
|
// eslint-disable-next-line no-empty-function
|
|
enc.on('data', () => {}); // Sink all writes
|
|
enc.pushAny(obj);
|
|
enc.stopRecording();
|
|
enc.removeAllListeners('data');
|
|
return enc._encodeAll([obj]);
|
|
}
|
|
|
|
/**
|
|
* Encode one JavaScript object using the given options in a way that
|
|
* is more resilient to objects being larger than the highWaterMark
|
|
* number of bytes. As with the other static encode functions, this
|
|
* will still use a large amount of memory. Use a stream-based approach
|
|
* directly if you need to process large and complicated inputs.
|
|
*
|
|
* @param {any} obj The object to encode.
|
|
* @param {import('./encoder').EncodingOptions} [options={}]
|
|
* Passed to the Encoder constructor.
|
|
* @returns {Promise<Buffer>} A promise for the encoded buffer.
|
|
*/
|
|
static encodeAsync(obj, options) {
|
|
return new Promise((resolve, reject) => {
|
|
/** @type {Buffer[]} */
|
|
const bufs = [];
|
|
const enc = new SharedValueEncoder(options);
|
|
// eslint-disable-next-line no-empty-function
|
|
enc.on('data', () => {});
|
|
enc.on('error', reject);
|
|
enc.on('finish', () => resolve(Buffer.concat(bufs)));
|
|
enc.pushAny(obj);
|
|
enc.stopRecording();
|
|
enc.removeAllListeners('data');
|
|
enc.on('data', buf => bufs.push(buf));
|
|
enc.pushAny(obj);
|
|
enc.end();
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = SharedValueEncoder;
|