Using jscodeshift, how can I transform
// Some code ...
const someObj = {
x: {
foo: 3
}
};
// Some more code ...
to
// Some code ...
const someObj = {
x: {
foo: 4,
bar: '5'
}
};
// Some more code ...
?
I have tried
module.exports = function(file, api, options) {
const j = api.jscodeshift;
const root = j(file.source);
return root
.find(j.Identifier)
.filter(path => (
path.node.name === 'someObj'
))
.replaceWith(JSON.stringify({foo: 4, bar: '5'}))
.toSource();
}
but I just end up with
// Some code ...
const someObj = {
{"foo": 4, "bar": "5"}: {
foo: 3
}
};
// Some more code ...
which suggests that replaceWith just changes the key instead of the value.
You have to search for the ObjectExpression rather than for the Identifier:
module.exports = function(file, api, options) {
const j = api.jscodeshift;
const root = j(file.source);
j(root.find(j.ObjectExpression).at(0).get())
.replaceWith(JSON.stringify({
foo: 4,
bar: '5'
}));
return root.toSource();
}
Demo
Related
const test = ({ foo = 'foo', bar = 'bar' } = {}) => {
return { foo, bar };
};
test(); // { foo: 'foo', bar: 'bar' }
test({}); // { foo: 'foo', bar: 'bar' }
test({ foo: 'cat' }); // { foo: 'cat', bar: 'bar' }
But if i rewrite it in TS
const test = ({
foo = 'foo',
bar = 'bar',
}: { foo: string; bar: string } = {}) => {
return { foo, bar };
};
= {} will cause error because of type mismatch (but as we see in first example — there is no undefined params and should be no type mismatch).
How to rewrite JS example in TS properly?
try this in your ts file :
const test = ({
foo = 'foo',
bar = 'bar',
}: { foo?: string; bar?: string } = {}) => {
return { foo, bar };
};
so basically I want to use createNode() within the callback of the file.walk() command, but when I do that, no nodes are created and you can't query the component type in graphiQL.
Uncommenting the other and commenting out the file section allows me to query the component (since it isn't in the callback.)
// Gatsby Node File
const file = require('file');
exports.sourceNodes = async ({ actions, createNodeId, createContentDigest }) => {
const { createNode } = actions;
// const components = [{
// key: 123,
// foo: `ywgavevw`,
// bar: `Baz`
// },
// {
// key: 456,
// foo: 'asdfsadf',
// bar: 'asdfasdf'
// }];
file.walk('./components/', (_, some, thing, files) => {
console.log(files);
let component = {
key: 456,
foo: 'asdfsadf',
bar: 'asdfasdf'
}
const nodeContent = JSON.stringify(component);
const nodeMeta = {
id: createNodeId(`kstat-component-${component.key}`),
parent: null,
children: [],
internal: {
type: `KstatComponent`,
mediaType: `text/html`,
content: nodeContent,
contentDigest: createContentDigest(component)
}
}
const node = Object.assign({}, component, nodeMeta);
createNode(node);
});
// components.forEach((component) => {
// const nodeContent = JSON.stringify(component);
// const nodeMeta = {
// id: createNodeId(`kstat-component-${component.key}`),
// parent: null,
// children: [],
// internal: {
// type: `KstatComponent`,
// mediaType: `text/html`,
// content: nodeContent,
// contentDigest: createContentDigest(component)
// }
// }
// const node = Object.assign({}, component, nodeMeta);
// createNode(node);
// });
}
On a higher level, I am trying to achieve creating a number of nodes based on files in the filesystem. Is there a less-crazy way of doing this? Should I consider something else? Thanks!
Have you tried awaiting for the callback?
await file.walk('./components/', (_, some, thing, files) => {
console.log(files);
let component = {
key: 456,
foo: 'asdfsadf',
bar: 'asdfasdf'
}
const nodeContent = JSON.stringify(component);
const nodeMeta = {
id: createNodeId(`kstat-component-${component.key}`),
parent: null,
children: [],
internal: {
type: `KstatComponent`,
mediaType: `text/html`,
content: nodeContent,
contentDigest: createContentDigest(component)
}
}
const node = Object.assign({}, component, nodeMeta);
createNode(node);
});
I can defined readFoo in Foo class:
var myFormat = 'foo'
class Foo {
[ "read" + ((format) => format)(myFormat) ]() {
return 123;
}
}
is there any way how to define function base on config like:
var config = ['foo1', 'foo2']
class Foo {
config.map((name) => {
[ "read" + ((format) => format)(name) ]() {
return 123;
}
}
}
Will create functions readFoo1 and readFoo2.
You can iterate through the array and assign to the prototype afterwards:
var config = ['foo1', 'foo2']
class Foo {}
for (const name of config) {
Foo.prototype["read" + name] = function() {
return 123;
};
}
const f = new Foo();
console.log(f.readfoo1());
Given an object:
const obj = {
a: {
b: {
c: {
d: 5
}
}
}
};
I want a function similar to lodash.get(obj, path), which returns the last defined variable in the path:
console.log(_.something(obj, 'a.b.c.d')) // 5, which is obj.a.b.c.d
// because obj.a.b.c.d is defined
console.log(_.something(obj, 'a.b.c.e')) // { d: 5 }, which is obj.a.b.c
// because the path is only defined up to obj.a.b.c
console.log(_.something(obj, 'a.b.f')) // { c: { d: 5 } }, which is a.b
// because the path is only defined up to a.b
I can write it myself, but I wonder if I can do it with an existing lodash function. I've looked through the documentation, but nothing caught my eye.
Here's a rough implementation of what i want:
const safeGet = (object, path) => {
const keys = path.split('.');
let current = object;
for (var i = 0; i < keys.length; i++){
const val = current[keys[i]]
if (val === undefined){
return current;
}
current = val;
}
}
There isn't a way to do that in Lodash by default, but here is a simpler function that I wrote than the one you currently have displayed. Hopefully this helps!
const obj1 = {
a: {
b: {
c: {
d: 5
}
}
}
};
const obj2 = {
a: {
b: {
c: {}
}
}
};
function getLastDefined(obj, searchPath) {
return _.get(obj, searchPath) || getLastDefined(obj, _.chain(searchPath).split('.').reverse().tail().reverse().join('.').value());
}
console.log(getLastDefined(obj1, 'a.b.c.d'));
console.log(getLastDefined(obj2, 'a.b.c.d'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
So heres the problem and heres the fiddle: https://jsfiddle.net/6zqco0mj/
const start = [{'a':'b'}, {'b':'c'}, {'c':'d'}, {'d':'e'}]
end =
{a:
{b:
{c:
{
d: {}
}
}
}
}
I have some code but not sure how would I dig deeper into an object
const start = [{'b':'c'}, {'a':'b'}, {'c':'d'}, {'d':'e'}];
const end = {};
function convert(key) {
const obj = getObj(key);
if(obj) {
const temp = {};
temp[obj[key]] = convert(obj[key]);
//findKey(obj[key]);
end[key] = temp;
}
}
function getObj(key) {
const foo = start.find((el, i) => { if(el[key]) { return el[key] } });
return foo;
}
function findKey(k) {
// what goes here?
}
convert('a');
console.log(end);
i think you went in the other way around for your aproach of recursivity; i gave it a try and this is what i got so far
const start = [{'b':'c'}, {'a':'b'}, {'c':'d'}, {'d':'e'}];
function convert(key, object) {
const obj = getObj(key);
if(obj) {
object[obj[key]] = {};
convert(obj[key], object[obj[key]]);
}
}
function getObj(key) {
const foo = start.find((el, i) => { if(el[key]) { return el[key] }});
return foo;
}
const end = { a: {}};
convert('a', end.a);
console.log(end);
You could use an object structure for collecting the data and build the tree.
This solutiotion works with unsorted data.
For getting the root properties, all keys and values are collected and only the subset is taken.
var data = [{ d: 'e' }, { b: 'c' }, { c: 'd' }, { a: 'b' }, { b : 'z' }],
tree = function (data) {
var keys = new Set,
values = new Set,
r = Object.create(null);
data.forEach(function (o) {
var [key, value] = Object.entries(o)[0];
keys.add(key);
values.add(value);
r[value] = r[value] || {};
r[key] = r[key] || {};
r[key][value] = r[key][value] || r[value];
});
values.forEach(v => keys.delete(v));
return Object.assign(...Array.from(keys, k => ({ [k]: r[k] })));
}(data);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }