1

I have a JavaScript object that contains functions and special values like Infinity, as well as strings and numbers:

const myObject = {
   propertyA: "my string",
   propertyB: 5,
   propertyC: () => "function returing a string",
   propertyD: Infinity
};

I would like to save it to a file so that the resulting content looks like this:

export default function () {
    return {
        propertyA: "my string",
        propertyB: 5,
        propertyC: () => "function returing a string",
        propertyD: Infinity
    };
}

I have tried to use JSON.stringify(), but that doesn't work with functions and special values, as those are not valid JSON:

writeFileSync('my-output.js', `
   export default function () {
       return ${ JSON.stringify(myObject) };
   }
`);

const myObject = {
   propertyA: "my string",
   propertyB: 5,
   propertyC: () => "function returing a string",
   propertyD: Infinity
};

console.log(JSON.stringify(myObject, null, 4));

Is there any other way to do this?

3
  • in what case json.stringify not working? Commented Sep 8, 2018 at 17:58
  • JSON only holds value properties, not functions. Commented Sep 8, 2018 at 18:02
  • Indeed, functions are not valid JSON but it still valid javascript object and I want to write a javascript file ;) Commented Sep 8, 2018 at 18:22

1 Answer 1

2

You need a different way to serialize your object other than JSON.stringify, maybe something like this:

// Pretty:

const TAB = '    ';
const BR = '\n';
const CBR = `,${ BR }`;

// Minified: 

// const TAB = '';
// const BR = '';
// const CBR = ',';

function arrayAsString(arr, depth=0) {
  const _ = TAB.repeat(depth - 1);
  const __ = _ + TAB;
  
  return `[${
    BR }${ arr.map(value =>
    `${ __ }${ serialize(value, depth) }`).join(CBR) }${
    BR }${ _ }]`;
}

function objectAsString(obj, depth=0) {
  const _ = TAB.repeat(depth - 1);
  const __ = _ + TAB;
  
  return `{${
    BR }${ Object.entries(obj).map(([key, value]) =>
    `${ __ }${ key }: ${ serialize(value, depth) }`).join(CBR) }${
    BR }${ _ }}`;
}

function serialize(value, depth=0) {
  if (value === null) {
    return `${ value }`;
  } else if (Array.isArray(value)) {
    return arrayAsString(value, depth + 1);
  } else if (typeof value === 'object') {
    return objectAsString(value, depth + 1);
  } else if (typeof value === 'string') {
    return `"${ value }"`;
  } else {
    return `${ value }`;
  }
}

const notStringifyableObject = {
  1: Infinity,
  str: "my string",
  num: 5,
  func: () => console.log('It works! 🎉'),
  mixArr: [{
    value: 1
  }, {
    value: 2
  }, 1, 2, [3, 4, 5]],
  arr: [1, 2, 3],
  obj: { foo: 'bar' },
  nil: null,
  und: undefined
};

const serialized = serialize(notStringifyableObject);

// This is what you would save in a file:
console.log(`export default ${ serialized };`);

// Check if it's actually working: 

eval(`test = ${ serialized }`);

test.func();
.as-console-wrapper {
  max-height: 100vh !important;
}

Then, once you have serialized your object, you can save its string representation to a file with some additional code so that you can later load it using require, as you have already done:

writeFileSync('my-output.js', `export default () => ${ serialized };`);

Or:

writeFileSync('my-output.js', `export default ${ serialized };`);

Note that's just a basic implementation and it doesn't support regular expression, dates, circular structures... So you might prefer to use a library like serialize-javascript or serialize-to-js instead of implementing your own solution.

Sign up to request clarification or add additional context in comments.

2 Comments

it crash when a value is null
@JoG Fixed. That's because typeof null is "object", so there should be a condition that checks and handles that inside serialize().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.