@tim-greller/xgettext-regex 0.4.1 → 0.5.0

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.
Files changed (3) hide show
  1. package/index.js +34 -32
  2. package/package.json +1 -1
  3. package/test/test.js +57 -0
package/index.js CHANGED
@@ -4,9 +4,8 @@ var Readable = require('stream').Readable
4
4
  var through = require('through2')
5
5
  var readdirp = require('readdirp')
6
6
  var once = require('once')
7
- var split = require('split')
8
7
  var xtend = require('xtend')
9
- var combine = require('stream-combiner')
8
+ const concat = require('concat-stream')
10
9
 
11
10
  function createDuplexStream (filename, opts) {
12
11
  filename = filename || ''
@@ -55,44 +54,47 @@ function createDuplexStream (filename, opts) {
55
54
  opts.regex = opts.regex || new RegExp("(?<=" + opts.fn + "\\(\\s*(?:(?:\"(?:[^\"]|\\\\.)*\"|'(?:[^']|\\\\.)*')\\s*,\\s*)*)(([\"'])(?:(?=(\\\\?))\\3.)*?\\2)(?=(?:\\s*,\\s*(?:\"(?:[^\"]|\\\\.)*\"|'(?:[^']|\\\\.)*'|[^\"')]+))*\\s*\\))", 'g')
56
55
  opts.regexTextCaptureIndex = opts.regexTextCaptureIndex || 1
57
56
 
58
- var lineNum = 1
57
+ var chunks = []
59
58
 
60
- return combine(
61
- split(),
62
- through(function (line, enc, cb) {
63
- line = line.toString()
59
+ return through(function (chunk, enc, cb) {
60
+ chunks.push(chunk)
61
+ cb()
62
+ }, function (cb) {
63
+ var content = Buffer.concat(chunks).toString()
64
+ var matches
65
+ var lineNum = 1
66
+ var scanIndex = 0
67
+ const relativeFilename = path.relative(process.cwd(), filename)
64
68
 
65
- var matches
66
- var first = true
69
+ opts.regex.lastIndex = 0
67
70
 
68
- while ((matches = opts.regex.exec(line)) !== null) {
69
- var entry = '\n'
71
+ while ((matches = opts.regex.exec(content)) !== null) {
72
+ var matchIndex = matches.index
70
73
 
71
- if (first) {
72
- const relativeFilename = path.relative(process.cwd(), filename)
73
- entry += '#: ' + relativeFilename + ':' + lineNum + '\n'
74
- first = false
75
- }
76
-
77
- var text = matches[opts.regexTextCaptureIndex]
78
-
79
- if (text[0] == "'") {
80
- text = text.slice(1, -1)
81
- text = text.replace(/\\'/g, "'")
82
- text = '"' + text.replace(/"/g, '\\"') + '"'
83
- }
74
+ while (scanIndex < matchIndex) {
75
+ if (content.charCodeAt(scanIndex) === 10) lineNum++
76
+ scanIndex++
77
+ }
84
78
 
85
- entry += 'msgid ' + text + '\n'
86
- entry += 'msgstr ' + text + '\n'
79
+ var text = matches[opts.regexTextCaptureIndex]
87
80
 
88
- this.push(entry)
81
+ if (text[0] == "'") {
82
+ text = text.slice(1, -1)
83
+ text = text.replace(/\\'/g, "'")
84
+ text = '"' + text.replace(/"/g, '\\"') + '"'
89
85
  }
90
86
 
91
- lineNum++
92
- opts.regex.lastIndex = 0
93
- cb()
94
- })
95
- )
87
+ this.push([
88
+ ``,
89
+ `#: ${relativeFilename}:${lineNum}`,
90
+ `msgid ${text}`,
91
+ `msgstr ${text}`
92
+ ].join('\n'))
93
+ }
94
+
95
+ opts.regex.lastIndex = 0
96
+ cb()
97
+ })
96
98
  }
97
99
 
98
100
  module.exports = createDuplexStream
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tim-greller/xgettext-regex",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Minimum viable xgettext .po file generator. Uses a configurable regex to get translation keys.",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/test/test.js CHANGED
@@ -83,6 +83,63 @@ test('Can change i18n function', function (t) {
83
83
  }))
84
84
  })
85
85
 
86
+ test('Can match i18n call spanning multiple lines', function (t) {
87
+ t.plan(2)
88
+
89
+ var src = new Readable
90
+ src._read = function () {
91
+ this.push('i18n.trn(\n')
92
+ this.push(' "multiline match",\n')
93
+ this.push(' "multiline matches",\n')
94
+ this.push(' stuff\n')
95
+ this.push(');\n')
96
+ this.push(null)
97
+ }
98
+
99
+ src
100
+ .pipe(xgettext('src', {fn: 'i18n.trn'}))
101
+ .pipe(concat({encoding: 'string'}, function (pot) {
102
+ t.ok(pot.indexOf('msgid "multiline match"') > -1, 'msgid "multiline match" exists')
103
+ t.ok(pot.indexOf('msgid "multiline matches"') > -1, 'msgid "multiline matches" exists')
104
+ t.end()
105
+ }))
106
+ })
107
+
108
+ test('Emits location line for each same-line match', function (t) {
109
+ t.plan(2)
110
+
111
+ var src = new Readable
112
+ src._read = function () {
113
+ this.push('_("first"); _("second")\n')
114
+ this.push(null)
115
+ }
116
+
117
+ src
118
+ .pipe(xgettext('src'))
119
+ .pipe(concat({encoding: 'string'}, function (pot) {
120
+ t.ok(pot.indexOf('#: src:1\nmsgid "first"') > -1, 'first entry has location line')
121
+ t.ok(pot.indexOf('#: src:1\nmsgid "second"') > -1, 'second entry has location line')
122
+ t.end()
123
+ }))
124
+ })
125
+
126
+ test('Emits location line for single match on line 4', function (t) {
127
+ t.plan(1)
128
+
129
+ var src = new Readable
130
+ src._read = function () {
131
+ this.push('Lorem\nIpsum\nDolor\n_("line four")\n')
132
+ this.push(null)
133
+ }
134
+
135
+ src
136
+ .pipe(xgettext('src'))
137
+ .pipe(concat({encoding: 'string'}, function (pot) {
138
+ t.ok(/#: src:4\r?\n(?:\r?\n)*msgid "line four"/.test(pot), 'single entry on line 4 has location line')
139
+ t.end()
140
+ }))
141
+ })
142
+
86
143
  test('Can create .pot from multiple files/directories', function (t) {
87
144
  t.plan(6)
88
145