Skip to content

Commit

Permalink
Support Dates and RegExps
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Sep 25, 2023
1 parent 0ff8003 commit df23de5
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 51 deletions.
93 changes: 46 additions & 47 deletions lib/serialize/other.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const t = require('@babel/types');
// Imports
const {createDependency} = require('./records.js'),
{URLContextSymbol, URLQuerySymbol} = require('../shared/globals.js'),
{REGEXP_TYPE, DATE_TYPE, registerSerializer} = require('./types.js'),
{firstMapKey} = require('./utils.js');

// Exports
Expand All @@ -37,33 +38,7 @@ module.exports = {
traceRegexp(regexp, record) {
this.traceProperties(regexp, record, undefined);
record.extra = {regexp: regexSourceGetter.call(regexp), flags: regexFlagsGetter.call(regexp)};
return this.serializeRegexp;
},

/**
* Serialize RegExp.
* @param {Object} record - Record
* @param {Object} record.extra - Extra props object
* @param {string} record.extra.regexp - Regex source string
* @param {string} record.extra.flags - Flags
* @returns {Object} - AST node
*/
serializeRegexp(record) {
const {extra} = record;
const node = t.regExpLiteral(extra.regexp, extra.flags);
/*
// TODO: Remove `lastIndex` property if matches default
const defaultProps = [{
key: 'lastIndex',
val: 0,
get: undefined,
set: undefined,
writable: true,
enumerable: false,
configurable: false
}];
*/
return this.wrapWithProperties(node, record, regexpProtoSetters);
return REGEXP_TYPE;
},

/**
Expand All @@ -74,28 +49,9 @@ module.exports = {
* @returns {Function} - Serializer function
*/
traceDate(date, record) {
const dateCtorRecord = this.traceValue(Date);
createDependency(record, dateCtorRecord);

this.traceProperties(date, record, undefined);
record.extra = {time: dateGetTime.call(date)};
return this.serializeDate;
},

/**
* Serialize Date.
* `Date` constructor will be 1st dependency.
* @param {Object} record - Record
* @param {Object} record.extra - Extra props object
* @param {number} record.extra.time - Time (from `date.getTime()`)
* @returns {Object} - AST node
*/
serializeDate(record) {
// `new Date(...)`
// TODO: Handle invalid dates (`record.extra.time` is `NaN`)
const dateCtorNode = this.serializeValue(firstMapKey(record.dependencies));
const node = t.newExpression(dateCtorNode, [t.numericLiteral(record.extra.time)]);
return this.wrapWithProperties(node, record, dateProtoSetters);
return DATE_TYPE;
},

/**
Expand Down Expand Up @@ -200,3 +156,46 @@ module.exports = {
throw new Error('Cannot serialize FinalizationRegistrys');
}
};

/**
* Serialize RegExp.
* @this {Object} Serializer
* @param {Object} record - Record
* @param {Object} record.extra - Extra props object
* @param {string} record.extra.regexp - Regex source string
* @param {string} record.extra.flags - Flags
* @returns {Object} - AST node
*/
function serializeRegexp(record) {
const node = t.regExpLiteral(record.extra.regexp, record.extra.flags);

const existingProps = [{
key: 'lastIndex',
valRecord: this.traceValue(0, null, null),
getRecord: undefined,
setRecord: undefined,
writable: true,
enumerable: false,
configurable: false
}];

return this.wrapWithProperties(node, record, this.regexpPrototypeRecord, existingProps);
}
registerSerializer(REGEXP_TYPE, serializeRegexp);

/**
* Serialize Date.
* @this {Object} Serializer
* @param {Object} record - Record
* @param {Object} record.extra - Extra props object
* @param {number} record.extra.time - Time (from `date.getTime()`)
* @returns {Object} - AST node
*/
function serializeDate(record) {
// `new Date(...)`
const {time} = record.extra,
timeNode = Number.isNaN(time) ? this.traceAndSerializeGlobal(NaN) : t.numericLiteral(time);
const node = t.newExpression(this.traceAndSerializeGlobal(Date), [timeNode]);
return this.wrapWithProperties(node, record, this.datePrototypeRecord, null);
}
registerSerializer(DATE_TYPE, serializeDate);
3 changes: 3 additions & 0 deletions lib/serialize/trace.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ module.exports = {
// TODO: Next properties should be defined elsewhere
this.nullRecord = this.traceValue(null, null, null);
this.nullRecord.setters = new Set();

this.undefinedRecord = this.traceValue(undefined, null, null);
this.objectPrototypeRecord = this.traceValue(Object.prototype, null, null);
this.arrayPrototypeRecord = this.traceValue(Array.prototype, null, null);
this.regexpPrototypeRecord = this.traceValue(RegExp.prototype, null, null);
this.datePrototypeRecord = this.traceValue(Date.prototype, null, null);

this.minusZeroRecord = null;
},
Expand Down
4 changes: 4 additions & 0 deletions lib/serialize/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const NO_TYPE = 0,
NEGATIVE_TYPE = PRIMITIVE_TYPE | 6, // TODO: Should this be a primitive?
OBJECT_TYPE = 16,
ARRAY_TYPE = OBJECT_TYPE | 1,
REGEXP_TYPE = OBJECT_TYPE | 2,
DATE_TYPE = OBJECT_TYPE | 3,
FUNCTION_TYPE = 32,
METHOD_TYPE = FUNCTION_TYPE | 1,
GLOBAL_TYPE = 64,
Expand Down Expand Up @@ -51,6 +53,8 @@ module.exports = {
NEGATIVE_TYPE,
OBJECT_TYPE,
ARRAY_TYPE,
REGEXP_TYPE,
DATE_TYPE,
FUNCTION_TYPE,
METHOD_TYPE,
GLOBAL_TYPE,
Expand Down
18 changes: 14 additions & 4 deletions test/other.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const {itSerializes, itSerializesEqual} = require('./support/index.js');
const urlsHaveContext = parseNodeVersion(process.version).major < 20,
itSerializesEqualIfUrlsHaveContext = urlsHaveContext ? itSerializesEqual : itSerializesEqual.skip;

describe.skip('RegExps', () => {
describe('RegExps', () => {
itSerializesEqual('with no flags', {
in: () => /^foo$/,
out: '/^foo$/',
Expand Down Expand Up @@ -49,7 +49,7 @@ describe.skip('RegExps', () => {
}
});

itSerializesEqual('RegExp subclass', {
itSerializesEqual.skip('RegExp subclass', {
in() {
class R extends RegExp {}
return new R('^foo$', 'gu');
Expand Down Expand Up @@ -77,7 +77,7 @@ describe.skip('RegExps', () => {
});
});

describe.skip('Dates', () => {
describe('Dates', () => {
itSerializesEqual('without extra props', {
in: () => new Date('01/01/2020 12:00:00'),
out: 'new Date(1577880000000)',
Expand All @@ -101,7 +101,17 @@ describe.skip('Dates', () => {
}
});

itSerializesEqual('Date subclass', {
itSerializes('invalid date', {
in: () => new Date(Number.MAX_SAFE_INTEGER),
out: 'new Date(NaN)',
validate(date) {
expect(date).toHavePrototype(Date.prototype);
expect(date).not.toBeValidDate();
expect(date.getTime()).toBeNaN();
}
});

itSerializesEqual.skip('Date subclass', {
in() {
class D extends Date {}
return new D('01/01/2020 12:00:00');
Expand Down

0 comments on commit df23de5

Please sign in to comment.