I am building a note taking app and for text I use the Slate.js editor. Twitter mention also works with stocks like this
It basically turns into a mention if /\$[a-zA-Z]{1,6}/ is true. What I have tried is to use the normalizeNode callback to change if the regex matches, by deleting the text and inserting a new node at that location but so far I've been unsuccessful.
Slate.js also has a nice set of examples but unfortunately haven't found any of them to demonstrate what I'm trying to do. What would be a good way to go about implementing this feature? Am I wrong to assume it's through using normalizeNode?
I solved this question when working on typed in emojis. For example, when a person typed :smile: we wanted the emoji to appear (a la Slack). The only differences with stock symbols and emojis would be the stock lookup and the usage of Transforms.insertNodes instead of Transforms.insertText.
The code below should be enough to help someone solve their use case. The key is startIndex and endIndex which targets the replacement.
Here's my solution:
editor.normalizeNode = entry => {
const [node, path] = entry;
if (!Text.isText(node)) {
return normalizeNode([node, path]);
}
const emojiMatch = node.text.match(EMOJI_REGEX);
if (!emojiMatch) {
return normalizeNode([node, path]);
}
const [searchMatch, colonMatch] = emojiMatch;
const { index: startIndex } = emojiMatch;
const endIndex = startIndex + searchMatch.length;
const [matchedEmoji] = emojiIndex.search(colonMatch).map(emoji => emoji) as BaseEmoji[];
if (!matchedEmoji) {
return normalizeNode([node, path]);
}
Transforms.insertText(editor, matchedEmoji.native, {
at: {
anchor: { path, offset: startIndex },
focus: { path, offset: endIndex },
}
})
normalizeNode([node, path]);
}
I'm writing a tiny reactive framework where I need to find out which subscriber needs updating. I'm implementing deep binding and I'm running into a wall how to find subscribers in an effective manner.
A stored variable can be an object, so for example
{
"user": {
"preferences": {
"food": "vegetarian"
}
}
}
You can get content to any level of this variable like this
getVar("user_preferences_food");
getVar("user_preferences");
However, you can also update it like that
setVar("user_preferences_food", "meat");
setVar("user_preferences", {"food": "meat"});
But in case of the first setVar (user_preferences_food) how can I find the subscriber using getVar("user_preferences"); or even getVar("user"); most effectively.
I already got it working by splitting the var on _ and then one by one concatting the next level and merging all the resulting arrays. But this is very resource intensive. Especially if there are a lot of subscribers. There must be a better way to find them that is less resource intensive.
Edit: I left out part of the explanation.
There is a subscribe method too
subscribe("user", cb);
subscribe("user_preferences", cb);
subscribe("user_preferences_food", cb);
These subscriptions are stored in an array in the framework.
As soon as "user_preferences_food" is updated for example, all subscriptions above should be triggered. But obviously not subscribe('othervar');
simplification of the subscribe method:
var subscriptions = [];
function subscribe(var, callback){
subscriptions.push({var: var, cb: callback});
}
Simplification of getVar
vars = {};
getVar(var){
// find var in vars with this logic: https://stackoverflow.com/a/18937118/249710
// current exact match on subscribers, but need the "parents, grandparents etc here
var toUpdate = _.where(subscriptions, {
"var" : var
});
_.each(toUpdate, function(sub){ sub.cb();});
}
Storing or getting data as part of the key I've already got covered. It is just finding the subscribers in the most effective manner
ps: this is in an environment where I cannot rely on ES6 yet (not all users have it enabled), there is no DOM but I do have underscore included. (Titanium app development platform)
I would try to make a list for the callbacks, so you loop trough one list so you dont have to search, because you know the list is there with all the callbacks.
So if you call setVar('user_prefs') you set a seperate list with the root var. in this case its the user.
if any object is changed with setVar (in depth or not) you go to you're root var, get the list and loop trough this list with the callbacks.
The beauty of this is you can set a list with the root var,
var cbList[FIRSTVAR] this contains all the callbacks. No searching just loop.
Its the mongoDb principle, the data is ready to go, you don't search because you know the list is already there.
You could split the string and use it for reduceing the object.
function getVar(object, path) {
return path
.split('_')
.reduce(function (o, k) {
return (o || {})[k];
}, object);
}
function setVar(object, path, value) {
var keys = path.split('_'),
last = keys.pop();
keys.reduce(function (o, k) {
return o[k] = o[k] || {};
}, object)[last] = value;
}
var object = { user: { preferences: { food: "vegetarian" } } };
console.log(getVar(object, "user_preferences_food"));
console.log(getVar(object, "user_preferences"));
setVar(object, "user_preferences_food", "meat");
console.log(object);
setVar(object, "user_preferences", {"food": "meat"});
console.log(object);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I ended up doing this:
var options = [];
var parts = key.split('_');
var string = parts[0];
_.each(parts, function(p, i){
if (i > 0) string += '_' + p;
options.push(string);
});
var toUpdate = _.filter(subscribers, function(sub){
if (sub.var.indexOf(key + '_') === 0) return true;
if (options.indexOf(sub.var) > -1) return true;
return false;
});
So checking with indexOf on the string to see if there are children. And building an array with parents so any layer is a match, and doing an indexOf on that as well. I think this is the least complicated method of implementing it
my attempts to build a module wrapping a collection fail
i have something like:
// topic: chess gaming
// file: src/core/Refs.js
const COLS = 'abcdefgh'.split('')
const ROWS = '12345678'.split('')
const ALL = new Map()
class Ref {
constructor (col, row) {
this.col = col
this.row = row
this.key = String(col + row)
}
// translate to ref to obtain another
// or null, if off-board
//
// ref.translate(0, 0) === ref (ok ?)
//
translate (dcol, drow) {
// compute something for dcol and drow
// ...
return ALL.get( COLS[colIdx] + ROWS[rowIdx] )
}
}
// the code which seems to not work propertly
for(let c of COLS) {
for(let r of ROWS) {
ALL.set(String(c + r), new Ref(c, r))
}
}
export default {
COLS, ROWS, ALL,
has (ref) {
return ALL.has(ref)
},
get (ref) {
return ALL.get(ref)
},
// trying to grant/warrant "immutability"
// for the "ALL" collection inside the module
keys() {
return [...ALL.keys()]
}
}
After I complie the module with Buble with correct flags (dangerousForOf, ..) and objectAssign
Then I test with karma + jasmine, the first test :
it ('should be 64-length array', function () {
expect (Refs.keys().length).toEqual(64)
})
will faim with 'expects 1 to equal 64', and a log of Refs.ALL seems to show an empty Map
althougth Refs.COLS and Refs.ROWS are properly initialized.
What's happening and how to fix it ?
EDIT:
#Bergi: of course, exposing Refs.ALL breaks the immutability, it was rather for debugging purposes
I'm not exactly sure how to capture test bundle output, but looking at gulp+rollup developpement bundle, the method keys() line :
return [...ALL.keys()]
was replaced by:
return [].concat(ALL.keys())
which produces an 1-element array containing a MapIterator, this breaking tests. putting something like :
return Array.from( ALL.keys() )
will fix the problem, but risks not to work properky in legacy browsers !
I have pushed the code on my repo : https://github.com/hefeust/colorchess-v2
Hoping this could help to fix the bug : how to convert spread (...) operator in source code to have a bundle with the correct Object.assign polyfill ?
Bublé does not support iterators, which is why it transpiles array literals with spread syntax to concatenations. Use Array.from instead (which is more descriptive anyway).
return Array.from( ALL.keys() ) will fix the problem, but risks not to work properly in legacy browsers!
That should be of no concern - you are using Map objects and their keys() method that returns an iterator, which won't work in legacy browsers either. If you plan to support them, you have to use a polyfill anyway - and you just would get a polyfill for Array.from as well.
function generate(count) {
var founded = false,
_sym = 'abcdefghijklmnopqrstuvwxyz1234567890',
str = '';
while(!founded) {
for(var i = 0; i < count; i++) {
str += _sym[parseInt(Math.random() * (_sym.length))];
}
base.getID(string, function(err, res) {
if(!res.length) {
founded = true; // How to do it?
}
});
}
return str;
}
How to set a variable value with database query callback? How I can do it?
Install NPM uuid package (sources: https://github.com/uuidjs/uuid):
npm install uuid
and use it in your code, e.g. with ES6 imports:
import { v4 as uuidv4, v6 as uuidv6 } from 'uuid';
uuidv4();
uuidv6();
Or with CommonJS requires:
const {
v1: uuidv1,
v4: uuidv4,
} = require('uuid');
uuidv1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'
uuidv4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'
For
The fastest possible way to create random 32-char string in Node is by using native crypto module:
const crypto = require("crypto");
const id = crypto.randomBytes(16).toString("hex");
console.log(id); // => f9b327e70bbcf42494ccb28b2d98e00e
Since Node 14.17.0 you can now use the built-in crypto module to generate UUIDs (UUIDv4 Flavored):
const { randomUUID } = require('crypto'); // Added in: node v14.17.0
console.log(randomUUID());
// '89rct5ac2-8493-49b0-95d8-de843d90e6ca'
For more you can explore
https://nodejs.org/api/crypto.html#crypto_crypto_randomuuid_options
Note: crypto.randomUUID is three times faster than uuid. And no need to add extra dependency.
Simple, time based, without dependencies:
(new Date()).getTime().toString(36)
or
Date.now().toString(36)
Output: jzlatihl
plus random number (Thanks to #Yaroslav Gaponov's answer)
(new Date()).getTime().toString(36) + Math.random().toString(36).slice(2)
Output jzlavejjperpituute
edit: shortid has been deprecated. The maintainers recommend to use nanoid instead.
Another approach is using the shortid package from npm.
It is very easy to use:
var shortid = require('shortid');
console.log(shortid.generate()); // e.g. S1cudXAF
and has some compelling features:
ShortId creates amazingly short non-sequential url-friendly unique
ids. Perfect for url shorteners, MongoDB and Redis ids, and any other
id users might see.
By default 7-14 url-friendly characters: A-Z, a-z, 0-9, _-
Non-sequential so they are not predictable.
Can generate any number of ids without duplicates, even millions per day.
Apps can be restarted any number of times without any chance of repeating an id.
It's been some time since I used node.js, but I think I might be able to help.
Firstly, in node, you only have a single thread and are supposed to use callbacks. What will happen with your code, is that base.getID query will get queued up by for execution, but the while loop will continusouly run as a busy loop pointlessly.
You should be able to solve your issue with a callback as follows:
function generate(count, k) {
var _sym = 'abcdefghijklmnopqrstuvwxyz1234567890',
var str = '';
for(var i = 0; i < count; i++) {
str += _sym[parseInt(Math.random() * (_sym.length))];
}
base.getID(str, function(err, res) {
if(!res.length) {
k(str) // use the continuation
} else generate(count, k) // otherwise, recurse on generate
});
}
And use it as such
generate(10, function(uniqueId){
// have a uniqueId
})
I haven't coded any node/js in around 2 years and haven't tested this, but the basic idea should hold – don't use a busy loop, and use callbacks. You might want to have a look at the node async package.
node-uuid is deprecated so please use uuid
npm install uuid --save
// Generate a v1 UUID (time-based)
const uuidV1 = require('uuid/v1');
uuidV1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'
// Generate a v4 UUID (random)
const uuidV4 = require('uuid/v4');
uuidV4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'
Npm link
More easy and without addition modules
Math.random().toString(26).slice(2)
If you use node v15.6.0+ us can use crypto.randomUUID([options]). Full documentation here.
to install uuid
npm install --save uuid
uuid is updated and the old import
const uuid = require('uuid/v4');
is not working and we should now use this import
const {v4: uuid} = require('uuid');
and for using it use as a function like this
const createdPlace = {
id: uuid(),
title,
description,
location: coordinates,
address,
creator
};
My 5 cents:
const crypto = require('crypto');
const generateUuid = () => {
return [4, 2, 2, 2, 6] // or 8-4-4-4-12 in hex
.map(group => crypto.randomBytes(group).toString('hex'))
.join('-');
};
Pono's string lacked hyphens sadly, so it did not conform to the uuid standard, which is what I believe most people came here for.
> generateUuid();
'143c8862-c212-ccf1-e74e-7c9afa78d871'
> generateUuid();
'4d02d4d6-4c0d-ea6b-849a-208b60bfb62e'
If some one needs cryptographic-strong UUID, there is solution for that as well.
https://www.npmjs.com/package/generate-safe-id
npm install generate-safe-id
Why not UUIDs?
Random UUIDs (UUIDv4) do not have enough entropy to be universally
unique (ironic, eh?). Random UUIDs have only 122 bits of entropy,
which suggests that a duplicate will occur after only 2^61 IDs.
Additionally, some UUIDv4 implementations do not use a
cryptographically strong random number generator.
This library generates 240-bit IDs using the Node.js crypto RNG,
suggesting the first duplicate will occur after generating 2^120 IDs.
Based on the current energy production of the human race, this
threshold will be impossible to cross for the foreseeable future.
var generateSafeId = require('generate-safe-id');
var id = generateSafeId();
// id == "zVPkWyvgRW-7pSk0iRzEhdnPcnWfMRi-ZcaPxrHA"
i want to use this
class GUID {
Generate() {
const hex = "0123456789ABCDEF";
const model = "xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx";
var str = "";
for (var i = 0; i < model.length; i++) {
var rnd = Math.floor(Math.random() * hex.length);
str += model[i] == "x" ? hex[rnd] : model[i] ;
}
return str.toLowerCase();
}
}
console.log(new GUID().Generate());
console.log(new GUID().Generate());
console.log(new GUID().Generate());
console.log(new GUID().Generate());
console.log(new GUID().Generate());
nanoid achieves exactly the same thing that you want.
Example usage:
const { nanoid } = require("nanoid")
console.log(nanoid())
//=> "n340M4XJjATNzrEl5Qvsh"
You can use urid package npm install urid
import urid from 'urid';
urid(); // qRpky22nKJ4vkbFZ
Read full docs here: https://www.npmjs.com/package/urid
// Set the size
urid(8); //ZDJLC0Zq
// Use the character set
urid('num'); // 4629118294212196
urid('alpha'); // ebukmhyiagonmmbm
urid('alphanum'); // nh9glmi1ra83979b
// Use size with character set
urid(12, 'alpha'); // wwfkvpkevhbg
// use custom character set
urid(6, '0123456789ABCDEF'); // EC58F3
urid('0123456789ABCDEF'); // 6C11044E128FB44B
// some more samples
urid() // t8BUFCUipSEU4Ink
urid(24) // lHlr1pIzAUAOyn1soU8atLzJ
urid(8, 'num') // 12509986
urid(8, 'alpha') // ysapjylo
urid(8, 'alphanum') // jxecf9ad
// example of all character sets
urid('num') // 5722278852141945
urid('alpha') // fzhjrnrkyxralgpl
urid('alphanum') // l5o4kfnrhr2cj39w
urid('Alpha') // iLFVgxzzUFqxzZmr
urid('ALPHA') // ALGFUIJMZJILJCCI
urid('ALPHANUM') // 8KZYKY6RJWZ89OWH
urid('hex') // 330f726055e92c51
urid('HEX') // B3679A52C69723B1
// custom character set
urid('ABCD-') // ACA-B-DBADCD-DCA
I am using the following and it is working fine plus without any third-party dependencies.
const {
randomBytes
} = require('crypto');
const uid = Math.random().toString(36).slice(2) + randomBytes(8).toString('hex') + new Date().getTime();
The solutions here are old and now deprecated: https://github.com/uuidjs/uuid#deep-requires-now-deprecated
Use this:
npm install uuid
//add these lines to your code
const { v4: uuidv4 } = require('uuid');
var your_uuid = uuidv4();
console.log(your_uuid);
used https://www.npmjs.com/package/uniqid in npm
npm i uniqid
It will always create unique id's based on the current time, process and machine name.
With the current time the ID's are always unique in a single process.
With the Process ID the ID's are unique even if called at the same
time from multiple processes.
With the MAC Address the ID's are unique even if called at the same
time from multiple machines and processes.
Features:-
Very fast
Generates unique id's on multiple processes and machines even if
called at the same time.
Shorter 8 and 12 byte versions with less uniqueness.
Extending from YaroslavGaponov's answer, the simplest implementation is just using Math.random().
Math.random()
Mathematically, the chances of fractions being the same in a real space [0, 1] is theoretically 0. Probability-wise it is approximately close to 0 for a default length of 16 decimals in node.js. And this implementation should also reduce arithmetic overflows as no operations are performed. Also, it is more memory efficient compared to a string as Decimals occupy less memory than strings.
I call this the "Fractional-Unique-ID".
Wrote code to generate 1,000,000 Math.random() numbers and could not find any duplicates (at least for default decimal points of 16). See code below (please provide feedback if any):
random_numbers = []
for (i = 0; i < 1000000; i++) {
random_numbers.push(Math.random());
//random_numbers.push(Math.random().toFixed(13)) //depends decimals default 16
}
if (i === 1000000) {
console.log("Before checking duplicate");
console.log(random_numbers.length);
console.log("After checking duplicate");
random_set = new Set(random_numbers); // Set removes duplicates
console.log([...random_set].length); // length is still the same after removing
}
Generates cryptographically strong pseudorandom data. The size argument is a number indicating the number of bytes to generate.
// Asynchronous
const {
randomBytes,
} = require('crypto');
randomBytes(256, (err, buf) => {
if (err) throw err;
console.log(`${buf.length} bytes of random data: unique random ID ${buf.toString('hex')}`);
});
Know more
Here is one benchmark for current solutions refer to nanoid benchmark
import { v4 as uuid4 } from 'uuid'
import benchmark from 'benchmark'
import shortid from 'shortid'
let suite = new benchmark.Suite()
suite
.add('crypto.randomUUID', () => {
crypto.randomUUID()
})
.add('nanoid', () => {
nanoid()
})
.add('uuid v4', () => {
uuid4()
})
.add("math.random", () => {
(new Date()).getTime().toString(36) + Math.random().toString(36).slice(2)
})
.add('crypto.randomBytes', () => {
crypto.randomBytes(32).toString('hex')
})
.add('shortid', () => {
shortid()
})
.on('cycle', event => {
let name = event.target.name
let hz = formatNumber(event.target.hz.toFixed(0)).padStart(10)
process.stdout.write(`${name}${pico.bold(hz)}${pico.dim(' ops/sec')}\n`)
})
.run()
The result is
node ./test/benchmark.js
crypto.randomUUID 13,281,440 ops/sec
nanoid 3,278,757 ops/sec
uuid v4 1,117,140 ops/sec
math.random 1,206,105 ops/sec
crypto.randomBytes 280,199 ops/sec
shortid 30,728 ops/sec
Test env:
2.6 GHz 6Cores Intel Core i7 MacOS
Node v16.17.0
For me, the easiest way to get unique id is the time, and I use hash for that example
const hash = require('object-hash');
const user = { ..., iat: Date.now() }
const user_id = hash(user)
console.log(user_id) // ex. 49686bab1a2276e0b1bd61ccc86f8156
and that is how I actually get unique identifier in any aspect. because in real world time never repeats.
const uniqueId = self.crypto.randomUUID();
console.log(uniqueId)
The randomUUID() method of the Crypto interface is used to generate a v4 UUID using a cryptographically secure random number generator.
Return A string containing a randomly generated, 36 character long v4 UUID.
let count = 0;
let previous = 0;
const generateUniqueId = () => {
const time = new Date().getTime()
count = time > previous ? 0 : (++count)
const uid = time + count
previous = uid
return uid
}