I want to be able to find target.json by passing a path to startingPoint.txt to a function in Node JS, given the following folder structure:
- root
- sub1
- sub2
startingPoint.txt
target.json
I've found a node package for it called find-up, but this is the kind of thing that probably takes no more than 6 lines of code.
export function findUp(start: Path, target: string): Path | undefined {
// this code here
}
const pathToTarget = findUp("root/sub1/sub2/startingPoint.txt", "target.json"/);
console.log(pathToTarget); // "root/target.json"
Old question I know, but I've just had to implement something similar and spent ages trying to find a good solution.
So, for future explorers, heres my solution using path and fs modules.
const PATH = require('path');
const FS = require('fs');
function findInPathAncestry(path, target) {
let current_directory_path = PATH.normalize(path).split(PATH.sep);
let result = false;
while(current_directory_path.length && !result) {
let current_path = current_directory_path.join(PATH.sep)+PATH.sep+target;
if(FS.existsSync(current_path)) {
result = current_path;
}
current_directory_path.pop();
}
return result;
}
usage example:
// example file structure:
// C:\
// | - path\
// | --- to\
// | ----- start\
// | ------- at\
// | ----- findme.txt
let start_location = "C:\path\to\start\at";
let target_file = "findme.txt";
console.log(findInPathAncestry(start_location, target_file));
// expected output:
// C:\path\to\findme.txt
// or false if file doesn't exist in path
the use of PATH.normalize and PATH.sep allows this to work in windows and unix environments
https://nodejs.org/api/path.html#path_path_sep
Here's what I have for now:
import { join, dirname } from 'path';
import { existsSync } from 'fs';
export let MAX_BACK_STEPS = 50;
export function findUp(start: string, target: string, boundary?: {
path: string,
inclusive: boolean,
}): string | null {
let currentDir = dirname(start);
let lastTry = false;
let backSteps = 0;
while (backSteps++) {
if (backSteps >= MAX_BACK_STEPS) {
console.error("Too many back steps");
return null;
}
if (boundary && boundary.path.includes(currentDir)) {
if (boundary.inclusive && lastTry === false) {
lastTry = true;
} else {
return null;
}
}
const targetTestPath = join(currentDir, target);
if (existsSync(targetTestPath)) {
return targetTestPath;
}
currentDir = join(currentDir, "../");
}
}
Related
I install a library/module but I am curious how they do it
const modules = require('abc');
const app = new modules('123');
const client = app.f1('abcdef').f2('ghi');
console.log(client.to());
const client2 = app.f1('1111111').f2('2222');
console.log(client2.to());
console.log(client.to());
result is 123:abcdef-ghi
result is 123:1111111-2222
result is 123:abcdef-ghi
how they did it?
i want to create that example lib/module
please give me sample code
Depending on your exact requirements, something like this seems to work:
let state = Symbol("private")
class App {
constructor(arg) {
this[state] = arg
}
f1 = arg => new App(this[state] + ":" + arg)
f2 = arg => new App(this[state] + "-" + arg)
to = () => this[state]
}
Here each of the chainable method returns a new instance of the class, each keeping the temporary result as a local state. The to() method returns that state.
This is what I use for doing function().anotherFunction()
function func() {
console.log("ran func")
return {
"anotherFunc": function () {
console.log("ran another func")
}
}
}
func().anotherFunc()
You can also just return a object
const returnData = {
"anotherFunc": function () {
console.log("ran another func")
}
}
function func() {
console.log("ran func")
return returnData
}
func().anotherFunc()
Example of use:
function word1(in_1) {
return {
"word2": function (in_2) {
console.log(`Inputs: ${in_1} ${in_2}`)
}
}
}
word1("Hello").word2("World")
// Expected output: Inputs: Hello World
I need to convert a Symbol to string in order to create a unique key in Redis, but I can't.
I've already tried to use Object.toString(obj) and String(obj) but I get errors or [Object] resultsĀ”.
This is the controller
const name = req.params.name;
let obj;
obj.data.name = {
[Op.like]: '%' + name + '%'
};
}
This is redis controller where I use stringify. I use obj as a parameter.
const hashed = crypto.createHmac('sha256', secretHashKey)
.update(JSON.stringify(obj))
.digest('hex');
I expect an output based on my parameter 'obj' but now it's not getting it so I can't create unique keys for different values.
Maybe a little bit too late, but I hope that somebody else find this useful.
I was looking for something exactly as you: use with Sequelize in a Redis cache.
Mine is TypeScript, convert to JavaScript just by removing the typings.
export function JsonStringifyWithSymbols(object: any, clean?: boolean): string {
return JSON.stringify(object, (_, value) => {
if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
const props = [...Object.getOwnPropertyNames(value), ...Object.getOwnPropertySymbols(value)];
const replacement: Record<string, any> = {};
for (const k of props) {
if (typeof k === 'symbol') {
replacement[`Symbol:${Symbol.keyFor(k)}`] = value[k];
} else {
replacement[k] = value[k];
}
}
return replacement;
}
return value;
});
}
If you're meaning these Symbols you can't convert them to a string.
They're created to be unique and "unreversable", so you can use them also for keep more "secure" various properties or methods. Example:
const a = Symbol('a')
class Foobar {
constructor (_a) {
this[a] = _a
}
}
const foobar = new Foobar('aaa')
console.log(foobar) // output: Foobar { [Symbol(a)]: 'aaa' }
const fake = Symbol('a')
foobar[fake] = 'fake'
console.log(foobar) // output: Foobar { [Symbol(a)]: 'aaa', [Symbol(a)]: 'fake' }
You can't corrupt the original one, unless you have the original Symbol.
Another example (info about the JSON.stringify here):
const a = Symbol('a')
const foobar = {}
foobar[a] = 'aaa'
console.log(foobar) // output: { [Symbol(a)]: 'aaa' }
console.log(JSON.stringify(foobar)) // output: {}
const fake = Symbol('a')
foobar[fake] = 'fake'
console.log(foobar) // output: { [Symbol(a)]: 'aaa', [Symbol(a)]: 'fake' }
Hope these info will help you.
How can I overwrite a module export value?
Currently I have this:
temp.js
let lastrsss = '';
module.exports = {
lastrsss
};
I try overwrite the value with this:
const temprss = require('../../temp');
temprss.lastrsss = "https://something.com";
It works, but same time it doesn't. I think it saves in memory or I don't know. It doesn't save in temp.js. How can I do that it will save in temp.js?
There are a couple ways to handle this. A nice clean one is to define a getter and setter:
temp.js
lastrsss = "hello"
module.exports = {
get lastrsss() {
return lastrsss
},
set lastrsss(val){
lastrsss = val
}
}
Now you can use them just like regular properties:
let tempres = require('./test2.js')
console.log(tempres.lastrsss) // hello
tempres.lastrsss = "goodbye"
console.log(tempres.lastrsss) // goodbye
Export a function to create and set a value in the lastrsss.
Try something like this:
function setLastrsss(value) {
let lastrsss = value;
return lastrsss;
}
module.exports = {
setLastrsss;
}
I am confused on how I can have two keys as strings and one works and the other doesn't. Error occurs in the line near the end:
println("Here's a (car.year) (car.make) (car.model)")
What is it about the "make" variable that could be causing the problem?
protocol NSCoding {
}
class Car:NSObject {
var year: Int = 0
var make: String = ""
var model: String = ""
override init() {
super.init()
}
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeInteger(year, forKey:"year")
aCoder.encodeObject(make, forKey:"make")
aCoder.encodeObject(model, forKey:"model")
}
init(coder aDecoder: NSCoder!) {
super.init()
year = aDecoder.decodeIntegerForKey("year")
make = aDecoder.decodeObjectForKey("make") as String
model = aDecoder.decodeObjectForKey("model") as String
}
}
class CarData {
func archiveData () {
var documentDirectories:NSArray
var documentDirectory:String
var path:String
var unarchivedCars:NSArray
var allCars:NSArray
// Create a filepath for archiving.
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
// Get document directory from that list
documentDirectory = documentDirectories.objectAtIndex(0) as String
// append with the .archive file name
path = documentDirectory.stringByAppendingPathComponent("swift_archiver_demo.archive")
var car1:Car! = Car()
var car2:Car! = Car()
var car3:Car! = Car()
car1.year = 1957
car1.make = "Chevrolet"
car1.model = "Bel Air"
car2.year = 1964
car2.make = "Dodge"
car2.model = "Polara"
car3.year = 1972
car3.make = "Plymouth"
car3.model = "Fury"
allCars = [car1, car2, car3]
// The 'archiveRootObject:toFile' returns a bool indicating
// whether or not the operation was successful. We can use that to log a message.
if NSKeyedArchiver.archiveRootObject(allCars, toFile: path) {
println("Success writing to file!")
} else {
println("Unable to write to file!")
}
// Now lets unarchive the data and put it into a different array to verify
// that this all works. Unarchive the objects and put them in a new array
unarchivedCars = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as NSArray
// Output the new array
for car : AnyObject in unarchivedCars {
println("Here's a \(car.year) \(car.make) \(car.model)")
}
}
}
Use downcasting in your for loop. The compiler needs to know that car is of type Car and not just AnyObject.
for car in cars as [Car!] {
println("Here's a \(car.year) \(car.make) \(car.model)")
}
I want to write a JS library and handle it like this:
var c1 = Module.Class();
c1.init();
var c1 = Module.Class();
c2.init();
And of course, c1 and c2 can not share the same variables.
I think I know how to do this with objects, it would be:
var Module = {
Class = {
init = function(){
...
}
}
}
But the problem is I can't have multiple instances of Class if I write in this way.
So I'm trying to achieve the same with function, but I don't think I'm doing it right.
(function() {
var Module;
window.Module = Module = {};
function Class( i ) {
//How can "this" refer to Class instead of Module?
this.initial = i;
}
Class.prototype.execute = function() {
...
}
//Public
Module.Class = Class;
})();
I don't have a clue if it's even possible, but I accept suggestions of other way to create this module.
I don't know if it's relevant also, but I'm using jQuery inside this library.
Usage:
var c1 = Module.Class("c");
var c2 = Module.Class("a");
var n = c1.initial(); // equals 'c'
c1.initial("s");
n = c1.initial(); // equals 's'
Module Code:
(function(window) {
var Module = window.Module = {};
var Class = Module.Class = function(initial)
{
return new Module.Class.fn.init(initial);
};
Class.fn = Class.prototype = {
init: function(initial) {
this._initial = initial;
},
initial: function(v){
if (v !== undefined) {
this._initial = v;
return this;
}
return this._initial;
}
};
Class.fn.init.prototype = Class.fn;
})(window || this);
This is using the JavaScript "Module" Design Pattern; which is the same design pattern used by JavaScript libraries such as jQuery.
Here's a nice tutorial on the "Module" pattern:
JavaScript Module Pattern: In-Depth