Socket
Socket
Sign inDemoInstall

markov-strings

Package Overview
Dependencies
1
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.1.0 to 3.0.0-beta.0

2

dist/index.d.ts
export declare type MarkovGenerateOptions = {
maxTries?: number;
prng?: any;
prng?: () => number;
filter?: (result: MarkovResult) => boolean;

@@ -5,0 +5,0 @@ };

{
"name": "markov-strings",
"version": "2.1.0",
"version": "3.0.0-beta.0",
"description": "A Markov string generator",

@@ -8,2 +8,3 @@ "main": "dist/index.js",

"scripts": {
"start": "tsc --watch",
"build": "tsc",

@@ -31,13 +32,13 @@ "test": "jest --coverage --coverageReporters=lcov --coverageReporters=html",

"devDependencies": {
"@types/jest": "^24.0.15",
"@types/lodash": "^4.14.136",
"@types/node": "^12.6.2",
"coveralls": "^3.0.5",
"jest": "^24.8.0",
"ts-jest": "^24.0.2",
"typescript": "^3.5.3"
"@types/jest": "^25.1.3",
"@types/lodash": "^4.14.149",
"@types/node": "^13.7.7",
"coveralls": "^3.0.9",
"jest": "^25.1.0",
"ts-jest": "^25.2.1",
"typescript": "^3.8.3"
},
"dependencies": {
"lodash": "^4.17.14"
"lodash": "^4.17.15"
}
}

@@ -7,3 +7,3 @@ [![Build Status](https://travis-ci.org/scambier/markov-strings.svg?branch=master)](https://travis-ci.org/scambier/markov-strings)

A simplistic Markov chain text generator.
A simplistic Markov chain text generator.
Give it an array of strings, and it will output a randomly generated string.

@@ -13,12 +13,12 @@

- [Markov-strings](#Markov-strings)
- [Prerequisites](#Prerequisites)
- [Installing](#Installing)
- [Usage](#Usage)
- [API](#API)
- [new Markov(data, [options])](#new-Markovdata-options)
- [.buildCorpus()](#buildCorpus)
- [Markov-strings](#markov-strings)
- [Prerequisites](#prerequisites)
- [Installing](#installing)
- [Usage](#usage)
- [API](#api)
- [new Markov([options])](#new-markovoptions)
- [.addData(data)](#adddatadata)
- [.generate([options])](#generateoptions)
- [Changelog](#Changelog)
- [Running the tests](#Running-the-tests)
- [Changelog](#changelog)
- [Running the tests](#running-the-tests)

@@ -43,5 +43,7 @@ ## Prerequisites

// Build the Markov generator
const markov = new Markov(data, { stateSize: 2 })
markov.buildCorpus()
const markov = new Markov({ stateSize: 2 })
// Add data for the generator
markov.addData(data)
const options = {

@@ -72,6 +74,22 @@ maxTries: 20, // Give up if I don't have a sentence after 20 tries (default is 10)

### new Markov(data, [options])
### new Markov([options])
Create a generator instance.
#### options
```js
{
stateSize: number
}
```
The `stateSize` is the number of words for each "link" of the generated sentence. `1` will output gibberish sentences without much sense. `2` is a sensible default for most cases. `3` and more can create good sentences if you have a corpus that allows it.
### .addData(data)
To function correctly, the Markov generator needs its internal data to be correctly structured. `.addData(data)` allows you add raw data, that is automatically formatted to fit the internal structure.
You can call `.addData(data)` as often as you need, with new data each time.
#### data

@@ -87,5 +105,7 @@

`[ 'lorem ipsum', 'dolor sit amet' ]`
```js
[ 'lorem ipsum', 'dolor sit amet' ]
```
or
or

@@ -99,19 +119,4 @@ ```js

#### options
Since `.addData(data)` can take some time (it loops for each word of each string), a non-blocking variant `.addDataAsync(data)` is conveniently available if you need it.
```js
{
stateSize: number
}
```
The `stateSize` is the number of words for each "link" of the generated sentence. `1` will output gibberish sentences without much sense. `2` is a sensible default for most cases. `3` and more can create good sentences if you have a corpus that allows it.
### .buildCorpus()
This function **must** be called to build the corpus for Markov generation.
It will iterate over all words from your `data` parameter to create an internal optimized structure.
Since `.buildCorpus()` can take some time (it loops for each word of each string), a non-blocking variant `.buildCorpusAsync()` is conveniently available if you need it.
### .generate([options])

@@ -146,2 +151,6 @@

#### 3.0.0
Refactoring to facilitate iterative construction of the corpus (multiple `.addData()` instead of a one-time `buildCorpus()`)
#### 2.1.0

@@ -148,0 +157,0 @@

import { assignIn, cloneDeep, flatten, includes, isEmpty, isString, slice, some, uniqBy } from 'lodash'
function sampleWithPRNG (array: Array<any>, prng: any = Math.random) {
function sampleWithPRNG<T>(array: T[], prng: () => number = Math.random): T | undefined {
const length = array == null ? 0 : array.length

@@ -8,5 +8,7 @@ return length ? array[Math.floor(prng() * length)] : undefined

export type MarkovInputData = Array<{ string: string }>
export type MarkovGenerateOptions = {
maxTries?: number,
prng?: any,
prng?: () => number,
filter?: (result: MarkovResult) => boolean

@@ -22,3 +24,3 @@ }

score: number,
refs: Array<{ string: string }>,
refs: MarkovInputData,
tries: number

@@ -29,3 +31,3 @@ }

words: string
refs: Array<{ string: string }>
refs: MarkovInputData
}

@@ -36,3 +38,3 @@

export default class Markov {
public data: Array<{ string: string }>
public data: MarkovInputData
public startWords: MarkovFragment[] = []

@@ -50,15 +52,7 @@ public endWords: MarkovFragment[] = []

*
* @param {(string[] | Array<{ string: string }>)} data An array of strings or objects.
* If 'data' is an array of objects, each object must have a 'string' attribute
* @param {MarkovConstructorOptions} [options={}]
* @memberof Markov
*/
constructor(data: string[] | Array<{ string: string }>, options: MarkovConstructorOptions = {}) {
// Format data if necessary
if (isString(data[0])) {
data = (data as string[]).map(s => ({ string: s }))
} else if (!data[0].hasOwnProperty('string')) {
throw new Error('Objects in your corpus must have a "string" property')
}
this.data = data as Array<{ string: string }>
constructor(options: MarkovConstructorOptions = {}) {
this.data = []

@@ -70,2 +64,17 @@ // Save options

public addData(rawData: MarkovInputData | string[]) {
// Format data if necessary
let input: MarkovInputData = []
if (isString(rawData[0])) {
input = (rawData as string[]).map(s => ({ string: s }))
}
else if (!rawData[0].hasOwnProperty('string')) {
throw new Error('Objects in your corpus must have a "string" property')
}
this.buildCorpus(input)
this.data = this.data.concat(input)
}
/**

@@ -76,6 +85,6 @@ * Builds the corpus. You must call this before generating sentences.

*/
public buildCorpus(): void {
private buildCorpus(data: MarkovInputData): void {
const options = this.options
this.data.forEach(item => {
data.forEach(item => {
const line = item.string

@@ -137,6 +146,6 @@ const words = line.split(' ')

*/
public buildCorpusAsync(): Promise<void> {
public addDataAsync(data: MarkovInputData | string[]): Promise<void> {
return new Promise((resolve, reject) => {
try {
this.buildCorpus()
this.addData(data)
resolve()

@@ -143,0 +152,0 @@ } catch (e) {

@@ -17,11 +17,5 @@ import { map, some } from 'lodash'

describe('Constructor', () => {
it('should throw an error if corpus is invalid', () => {
expect(() => {
// @ts-ignore
const markov = new Markov([{}])
}).toThrowError()
})
it('should have a default stateSize', () => {
const markov = new Markov(data)
const markov = new Markov()
expect(markov.options.stateSize).toBe(2)

@@ -31,3 +25,3 @@ })

it('should save a different stateSize', () => {
const markov = new Markov(data, { stateSize: 3 })
const markov = new Markov({ stateSize: 3 })
expect(markov.options.stateSize).toBe(3)

@@ -37,7 +31,7 @@ })

describe('Build the corpus', () => {
describe('Adding data', () => {
it('should build synchronously', () => {
const markov = new Markov(data)
const markov = new Markov()
expect(markov.corpus).toEqual({})
markov.buildCorpus()
markov.addData(data)
expect(markov.corpus).not.toEqual({})

@@ -47,14 +41,23 @@ })

it('should build asynchronously', async () => {
const markov = new Markov(data)
markov.buildCorpus = jest.fn()
await markov.buildCorpusAsync()
expect(markov.buildCorpus).toHaveBeenCalled()
const markov = new Markov()
markov.addData = jest.fn()
await markov.addDataAsync(data)
expect(markov.addData).toHaveBeenCalled()
})
it('should throw an error if the data structure is invalid', () => {
const markov = new Markov()
expect(() => {
// @ts-ignore
markov.addData([{}])
}).toThrowError()
})
})
describe('After building the corpus', () => {
describe('After adding data', () => {
let markov: Markov
beforeEach(() => {
markov = new Markov(data)
markov.buildCorpus()
markov = new Markov()
markov.addData(data)
})

@@ -94,28 +97,22 @@

})
})
describe('The corpus itself', () => {
let markov: Markov
beforeEach(() => {
markov = new Markov(data)
markov.buildCorpus()
describe('The corpus itself', () => {
it('should have the right values for the right keys', () => {
const corpus = markov.corpus
expect(some(corpus['Lorem ipsum'], { words: 'dolor sit' })).toBeTruthy()
expect(
some(corpus['Lorem ipsum'], { words: 'duplicate start' })
).toBeTruthy()
expect(
some(corpus['tempor, erat'], { words: 'vel lacinia' })
).toBeTruthy()
})
})
it('should have the right values for the right keys', () => {
const corpus = markov.corpus
expect(some(corpus['Lorem ipsum'], { words: 'dolor sit' })).toBeTruthy()
expect(
some(corpus['Lorem ipsum'], { words: 'duplicate start' })
).toBeTruthy()
expect(
some(corpus['tempor, erat'], { words: 'vel lacinia' })
).toBeTruthy()
})
})
describe('The sentence generation', () => {
describe('The sentence generator', () => {
let markov: Markov
beforeEach(() => {
markov = new Markov(data)
markov.buildCorpus()
markov = new Markov()
markov.addData(data)
})

@@ -130,3 +127,3 @@

it('should throw an error if the corpus is not built', () => {
markov = new Markov(data)
markov = new Markov()
expect(() => {

@@ -133,0 +130,0 @@ markov.generate()

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc