natural 8.0.1 → 8.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,7 +44,7 @@ jobs:
44
44
 
45
45
  strategy:
46
46
  matrix:
47
- node-version: [16.x, 18.x, 20.x]
47
+ node-version: [20.x, 22.x, 24.x]
48
48
  # See supported Node.js release schedule at
49
49
  #https://nodejs.org/en/about/releases/
50
50
 
@@ -60,8 +60,14 @@ jobs:
60
60
  - name: Clean install
61
61
  run: npm ci
62
62
 
63
+ - name: Lint
64
+ run: npm run lint
65
+
63
66
  - name: Build
64
67
  run: npm run build
68
+
69
+ - name: ESM smoke test
70
+ run: npm run smoke:esm
65
71
 
66
72
  - name: Run Istanbul coverage
67
73
  run: npm run coverage
@@ -25,7 +25,7 @@
25
25
  const DEBUG = false
26
26
 
27
27
  // Afinn
28
- const englishAfinnVoca = require('afinn-165')
28
+ const englishAfinnVoca = require('afinn-165').afinn165
29
29
  const spanishAfinnVoca = require('./Spanish/afinnShortSortedSpanish.json')
30
30
  const portugueseAfinnVoca = require('./Portuguese/afinnShortSortedPortuguese.json')
31
31
 
@@ -27,7 +27,7 @@ declare interface RegionsType {
27
27
  }
28
28
 
29
29
  export declare interface Stemmer {
30
- stem: (token: string) => string
30
+ stem: (token: string, options?: any) => string
31
31
  addStopWord: (stopWord: string) => void
32
32
  addStopWords: (moreStopWords: string[]) => void
33
33
  removeStopWord: (stopWord: string) => void
@@ -21,7 +21,7 @@ PorterStemmer.stem = stemm
21
21
  module.exports = PorterStemmer
22
22
 
23
23
  /* by Joder Illi, Snowball mailing list */
24
- function stemm (word) {
24
+ function stemm (word, options = {}) {
25
25
  /*
26
26
  Put u and y between vowels into upper case
27
27
  */
@@ -257,6 +257,9 @@ function stemm (word) {
257
257
  */
258
258
  word = word.replace(/U/g, 'u')
259
259
  word = word.replace(/Y/g, 'y')
260
+ if (options.preserveUmlauts) {
261
+ return word
262
+ }
260
263
  word = word.replace(/ä/g, 'a')
261
264
  word = word.replace(/ö/g, 'o')
262
265
  word = word.replace(/ü/g, 'u')
@@ -41,13 +41,18 @@ function escapeRegExp (string) {
41
41
  }
42
42
 
43
43
  class SentenceTokenizer extends Tokenizer {
44
- constructor (abbreviations) {
44
+ constructor (abbreviations, trimSentences) {
45
45
  super()
46
46
  if (abbreviations) {
47
47
  this.abbreviations = abbreviations
48
48
  } else {
49
49
  this.abbreviations = []
50
50
  }
51
+ if (trimSentences === undefined) {
52
+ this.trimSentences = true
53
+ } else {
54
+ this.trimSentences = trimSentences
55
+ }
51
56
  this.replacementMap = null
52
57
  this.replacementCounter = 0
53
58
  }
@@ -181,7 +186,7 @@ class SentenceTokenizer extends Tokenizer {
181
186
  const trimmedSentences = this.trim(newSentences)
182
187
  DEBUG && console.log('Phase 7: trimming array of empty sentences: ' + JSON.stringify(trimmedSentences))
183
188
 
184
- const trimmedSentences2 = trimmedSentences.map(sent => sent.trim())
189
+ const trimmedSentences2 = trimmedSentences.map(sent => this.trimSentences ? sent.trim() : sent)
185
190
  DEBUG && console.log('Phase 8: trimming sentences from surrounding whitespace: ' + JSON.stringify(trimmedSentences2))
186
191
  DEBUG && console.log('---End of sentence tokenization--------------------------')
187
192
  DEBUG && console.log('---Replacement map---------------------------------------')
@@ -0,0 +1,22 @@
1
+ const knownAbbreviations = [
2
+ // Titles (Sir, Doctor, etc)
3
+ 'Sr.', 'Sra.', 'Srta.', 'Srs.', 'Sras.', 'Dr.', 'Dra.', 'Drs.', 'Dras.',
4
+ 'Lic.', 'Licda.', 'Licdo.', 'Licds.', 'Ings.', 'Ing.', 'Arq.', 'Arqs.', 'Prof.', 'Profa.', 'Profs.', 'Profas.',
5
+
6
+ // Generals
7
+ 'etc.', 'e.g.', 'i.e.', 'p.ej.', 'p.e.', 'a.m.', 'p.m.',
8
+ 'núm.', 'núms.', 'n.os', 'n.os.', 'ud.', 'uds.',
9
+ 'c/ap.', 'c/u.', 's/n.', 'av.', 'pto.', 'ptos.', 'pág.', 'págs.', 'vol.', 'vols.', 'ed.', 'eds.', 'cap.', 'caps.',
10
+ 'mín.', 'máx.', 'aprox.', 'ant.', 'sig.', 'hist.', 'biol.', 'quím.', 'mat.', 'psic.',
11
+ 'adj.', 'adv.', 'art.', 'arts.', 'vb.', 'vbs.', 'sust.', 'susts.', 'prep.', 'preps.',
12
+
13
+ // Legal written in Spanish
14
+ 'Art.', 'Arts.', 'Inc.', 'Incs.', 'const.', 'Cód.', 'Códs.',
15
+ 'C.C.', 'C.P.', 'C.N.', 'DNU.', 'DTO.', 'Res.', 'Disp.', 'Disps.', 'C.P.C.C.', 'C.C.Y.C.',
16
+ 'expte.', 'exptes.', 'fs.', 'fjs.', 'op.', 'cf.', 'cit.', 'loc. cit.', 'ut supra.', 'vgr.', 'ap.', 'cfr.', 'ss.',
17
+
18
+ // Latin-legal written in Spanish
19
+ 'et al.', 'ibid.', 'ibíd.', 'op. cit.', 'loc. cit.', 'id.', 'vs.', 'a priori.', 'a posteriori.', 'sine die.'
20
+ ]
21
+
22
+ exports.knownAbbreviations = knownAbbreviations
@@ -25,6 +25,9 @@ THE SOFTWARE.
25
25
 
26
26
  export let stopwords: string[]
27
27
 
28
+ export let abbreviations: string[]
29
+ export let abbreviationsEs: string[]
30
+
28
31
  declare class Bag<T> {
29
32
  add (element: T): Bag<T>
30
33
  isEmpty (): boolean
@@ -24,6 +24,7 @@ THE SOFTWARE.
24
24
 
25
25
  exports.stopwords = require('./stopwords').words
26
26
  exports.abbreviations = require('./abbreviations_en').knownAbbreviations
27
+ exports.abbreviations_es = require('./abbreviations_es').knownAbbreviations
27
28
  exports.ShortestPathTree = require('./shortest_path_tree')
28
29
  exports.LongestPathTree = require('./longest_path_tree')
29
30
  exports.DirectedEdge = require('./directed_edge')
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "natural",
3
3
  "description": "General natural language (tokenizing, stemming (English, Russian, Spanish), part-of-speech tagging, sentiment analysis, classification, inflection, phonetics, tfidf, WordNet, jaro-winkler, Levenshtein distance, Dice's Coefficient) facilities for node.",
4
- "version": "8.0.1",
4
+ "version": "8.1.1",
5
5
  "homepage": "https://github.com/NaturalNode/natural",
6
6
  "repository": {
7
7
  "type": "git",
@@ -11,66 +11,46 @@
11
11
  "node": ">=0.4.10"
12
12
  },
13
13
  "dependencies": {
14
- "afinn-165": "^1.0.2",
14
+ "afinn-165": "^2.0.2",
15
15
  "afinn-165-financialmarketnews": "^3.0.0",
16
16
  "apparatus": "^0.0.10",
17
- "dotenv": "^16.4.5",
18
- "http-server": "^14.1.1",
17
+ "dotenv": "^17.3.1",
19
18
  "memjs": "^1.3.2",
20
- "mongoose": "^8.2.0",
21
- "pg": "^8.11.3",
22
- "redis": "^4.6.13",
23
- "safe-stable-stringify": "^2.2.0",
19
+ "mongoose": "^9.2.1",
20
+ "pg": "^8.18.0",
21
+ "redis": "^5.11.0",
22
+ "safe-stable-stringify": "^2.5.0",
24
23
  "stopwords-iso": "^1.1.0",
25
- "sylvester": "^0.0.12",
26
- "underscore": "^1.9.1",
27
- "uuid": "^9.0.1",
28
- "wordnet-db": "^3.1.11"
24
+ "sylvester": "^0.0.21",
25
+ "underscore": "^1.13.0",
26
+ "uuid": "^13.0.0",
27
+ "wordnet-db": "^3.1.14"
29
28
  },
30
29
  "devDependencies": {
31
- "@rollup/plugin-commonjs": "^25.0.8",
30
+ "@rollup/plugin-commonjs": "^29.0.0",
32
31
  "@rollup/plugin-json": "^6.1.0",
33
- "@rollup/plugin-node-resolve": "^15.2.3",
34
- "@types/jasmine": "^5.1.4",
35
- "@types/node": "^18.11.18",
32
+ "@rollup/plugin-node-resolve": "^16.0.3",
33
+ "@types/jasmine": "^6.0.0",
34
+ "@types/node": "^25.2.3",
36
35
  "@typescript-eslint/eslint-plugin": "^6.21.0",
37
- "browserfs": "^1.4.3",
38
- "cross-env": "^7.0.3",
36
+ "cross-env": "^10.1.0",
39
37
  "eslint": "^8.57.0",
40
38
  "eslint-config-standard-with-typescript": "^43.0.1",
41
- "eslint-plugin-import": "^2.29.1",
42
- "eslint-plugin-n": "^15.7.0",
43
- "eslint-plugin-promise": "^6.1.1",
44
- "gulp": "^4.0.2",
45
- "gulp-jasmine": "^4.0.0",
46
- "gulp-jasmine-browser": "^4.1.0",
47
- "jasmine": "^3.3.1",
48
- "jasmine-core": "^3.3.0",
49
- "lint": "^0.8.19",
39
+ "eslint-plugin-import": "^2.32.0",
40
+ "eslint-plugin-n": "^16.6.2",
41
+ "eslint-plugin-promise": "^6.6.0",
42
+ "jasmine": "^6.0.0",
43
+ "jasmine-core": "^6.0.0",
50
44
  "ncp": "^2.0.0",
51
45
  "nyc": "^15.1.0",
52
46
  "pegjs": "^0.10.0",
53
- "proxyquire": "^1.8.0",
54
- "rimraf": "^2.6.3",
55
- "rollup": "^4.18.0",
56
- "sinon": "^1.12.2",
47
+ "proxyquire": "^2.1.3",
48
+ "rimraf": "^5.0.0",
49
+ "rollup": "^4.57.1",
50
+ "sinon": "^17.0.0",
57
51
  "source-map-support": "^0.5.21",
58
- "standard": "^16.0.4",
59
52
  "ts-node": "^10.9.2",
60
- "ts-standard": "^12.0.2",
61
- "typescript": "^5.4.2",
62
- "uubench": "^0.0.1",
63
- "webpack": "^4.29.0",
64
- "webpack-stream": "^5.2.1"
65
- },
66
- "standard": {
67
- "ignore": [
68
- "/lib/natural/brill_pos_tagger/lib/TF_Parser.js",
69
- "/lib/natural/tokenizers/parser_sentence_tokenizer.js"
70
- ],
71
- "env": {
72
- "jasmine": true
73
- }
53
+ "typescript": "^5.9.3"
74
54
  },
75
55
  "jscpd": {
76
56
  "ignore": [
@@ -86,8 +66,8 @@
86
66
  "clean": "rimraf *~ #* *classifier.json dist io_spec/tmp/*.json coverage",
87
67
  "test_io": "jasmine --random=false io_spec/*_spec.js",
88
68
  "test": "cross-env NODE_PATH=. jasmine --random=false dist/cjs/spec/*_spec.js",
69
+ "smoke:esm": "node spec/esm/smoke.mjs",
89
70
  "coverage": "nyc --no-clean npm run test && nyc --no-clean npm run test_io",
90
- "test_browser": "cross-env NODE_PATH=. node ./node_modules/gulp/bin/gulp.js",
91
71
  "lint": "eslint . --ext .ts"
92
72
  },
93
73
  "license": "MIT",
package/rollup.config.mjs CHANGED
@@ -1,19 +1,51 @@
1
1
  import resolve from '@rollup/plugin-node-resolve'
2
2
  import commonjs from '@rollup/plugin-commonjs'
3
3
  import json from '@rollup/plugin-json'
4
+ import { builtinModules, createRequire } from 'node:module'
5
+
6
+ const require = createRequire(import.meta.url)
7
+ const pkg = require('./package.json')
8
+
9
+ const deps = Object.keys(pkg.dependencies || {})
10
+ const peerDeps = Object.keys(pkg.peerDependencies || {})
11
+
12
+ const jsonEntryDeps = new Set(
13
+ deps.filter((dep) => {
14
+ try {
15
+ return require.resolve(dep).endsWith('.json')
16
+ } catch {
17
+ return false
18
+ }
19
+ })
20
+ )
21
+ const nodeBuiltins = builtinModules.flatMap((name) => (
22
+ name.startsWith('node:') ? [name, name.slice(5)] : [name, `node:${name}`]
23
+ ))
24
+
25
+ const external = (id) => (
26
+ nodeBuiltins.includes(id) ||
27
+ deps.some((dep) => (id === dep || id.startsWith(`${dep}/`)) && !jsonEntryDeps.has(dep)) ||
28
+ peerDeps.some((dep) => id === dep || id.startsWith(`${dep}/`))
29
+ )
4
30
 
5
31
  export default {
6
32
  input: 'lib/natural/index.js', // Your entry point
33
+ external,
7
34
  output: {
8
35
  dir: 'dist/esm', // Output directory for ESM build
9
36
  format: 'esm', // Output format as ESM
10
- sourcemap: true // Optional: generate source maps
37
+ sourcemap: true, // Optional: generate source maps
38
+ preserveModules: true,
39
+ preserveModulesRoot: 'lib/natural'
11
40
  },
12
41
  plugins: [
13
42
  resolve({
14
43
  preferBuiltins: true // Prefer Node.js built-in modules over local modules
15
44
  }), // Resolve modules from node_modules
16
- commonjs(), // Convert CommonJS modules to ES modules
45
+ commonjs({
46
+ esmExternals: (id) => !nodeBuiltins.includes(id),
47
+ requireReturnsDefault: 'auto'
48
+ }), // Convert CommonJS modules to ES modules
17
49
  json() // Add the JSON plugin to handle JSON imports
18
50
  ]
19
51
  }
package/gulpfile.js DELETED
@@ -1,34 +0,0 @@
1
- /*
2
- Copyright (c) 2020, Hugo W.L. ter Doest
3
-
4
- Permission is hereby granted, free of charge, to any person obtaining a copy
5
- of this software and associated documentation files (the "Software"), to deal
6
- in the Software without restriction, including without limitation the rights
7
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- copies of the Software, and to permit persons to whom the Software is
9
- furnished to do so, subject to the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be included in
12
- all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- THE SOFTWARE.
21
- */
22
-
23
- const { src } = require('gulp')
24
- const jasmineBrowser = require('gulp-jasmine-browser')
25
- const webpackStream = require('webpack-stream')
26
-
27
- exports.default = function () {
28
- return src(['spec/*_spec.js'])
29
- .pipe(webpackStream(require('webpack.config')))
30
- .pipe(jasmineBrowser.specRunner({ random: false }))
31
- // Server is at http://localhost:8888
32
- // In the options tab uncheck "run tests in random order"
33
- .pipe(jasmineBrowser.server())
34
- }
package/webpack.config.js DELETED
@@ -1,50 +0,0 @@
1
- const webpack = require('webpack')
2
-
3
- module.exports = {
4
-
5
- mode: 'none',
6
-
7
- target: 'web',
8
-
9
- resolve: {
10
- extensions: ['.js', '.json'],
11
-
12
- modules: ['node_modules', '.'],
13
-
14
- // Use our versions of Node modules.
15
- alias: {
16
- fs: 'browserfs/dist/shims/fs.js',
17
- buffer: 'browserfs/dist/shims/buffer.js',
18
- path: 'browserfs/dist/shims/path.js',
19
- processGlobal: 'browserfs/dist/shims/process.js',
20
- bufferGlobal: 'browserfs/dist/shims/bufferGlobal.js',
21
- bfsGlobal: require.resolve('browserfs')
22
- }
23
- },
24
-
25
- // REQUIRED to avoid issue "Uncaught TypeError: BrowserFS.BFSRequire is not a function"
26
- // See: https://github.com/jvilk/BrowserFS/issues/201
27
- module: {
28
- noParse: /browserfs\.js/
29
- },
30
-
31
- watch: false,
32
-
33
- output: { filename: 'spec.js' },
34
-
35
- plugins: [
36
- // Expose BrowserFS, process, and Buffer globals.
37
- // NOTE: If you intend to use BrowserFS in a script tag, you do not need
38
- // to expose a BrowserFS global.
39
- new webpack.ProvidePlugin({ BrowserFS: 'bfsGlobal', process: 'processGlobal', Buffer: 'bufferGlobal' })
40
- ],
41
-
42
- // DISABLE Webpack's built-in process and Buffer polyfills!
43
- node: {
44
- process: false,
45
- Buffer: false
46
- },
47
-
48
- stats: 'normal'
49
-
50
- }