@frsource/frs-replace 4.1.0 → 5.0.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.
package/bin/cli.js DELETED
@@ -1,148 +0,0 @@
1
- #!/usr/bin/env node
2
- const replaceSync = require('../sync');
3
-
4
- (
5
- ~process.argv.indexOf('--no-stdin')
6
- ? Promise.resolve()
7
- : require('get-stdin')()
8
- ).then((stdin) => {
9
- const isPiped = !!stdin
10
-
11
- if (isPiped) {
12
- process.argv.push('-c')
13
- process.argv.push(stdin) // threat piped data as value for --content option
14
- }
15
-
16
- const isContentPresent = ~process.argv.indexOf('--content') || ~process.argv.indexOf('-c')
17
- const isHelpPresent = ~process.argv.indexOf('--help') || ~process.argv.indexOf('-h')
18
-
19
- const argv = require('yargs')
20
- .parserConfiguration({
21
- 'camel-case-expansion': false
22
- })
23
- .scriptName('frs-replace')
24
- .usage('$0 <needle> <replacement> [options]', 'Replace matching parts of string with replacement string/function', (yargs) => {
25
- yargs
26
- .positional('needle', {
27
- describe: 'String which is passed as a first parameter to RegExp constructor',
28
- type: 'string',
29
- demand: true
30
- })
31
- .positional('replacement', {
32
- describe: 'String or path to replacement function file (see --replace-fn switch for details)',
33
- type: 'string',
34
- demand: true
35
- })
36
- .example('$0 a b -i foo.js -o foo_replaced.js',
37
- 'Replaces all "a" occurences with "b" from given foo.js and save result to foo_replaced.js')
38
- .example('<read file> | $0 a b > <output-file-path>',
39
- 'Replaces all "a" occurences with "b" from stream and save it to output file')
40
- .example('<read file> | $0 a b | <next-command>',
41
- 'Replaces all "a" occurences with "b" from stream and pass it through the stream to next command')
42
- .example('$0 a b -i foo.js | <next-command>',
43
- 'Both pipe & options styles can be mixed together, here - getting input from "i" argument and passing output down the stream to next command')
44
- .example('$0 a b --content abcd -o foo_replaced.js',
45
- 'Replace all "a" occurences with "b" in given "abcd" and save result (which is "bbcd") to foo_replaced.js')
46
- })
47
-
48
- .option('f')
49
- .alias('f', 'flags')
50
- .describe('f', 'RegExp flags used together with `needle` positional (supporting g, i & m)')
51
- .nargs('f', 1)
52
- .choices('f', ['', 'g', 'm', 'i', 'gm', 'gi', 'mi', 'mg', 'ig', 'im', 'gmi', 'gim', 'mig', 'mgi', 'igm', 'img'])
53
- .default('f', 'g')
54
- .coerce('f', arg => arg.trim())
55
- .option('i', { demandOption: !isContentPresent && !isHelpPresent })
56
- .alias('i', 'input')
57
- .describe('i', 'Path to files or fast-glob pattern pointing to files to read & replace from')
58
- .array('i')
59
-
60
- .option('i-read-opts')
61
- .describe('i-read-opts', 'Passed to fs.readFileSync when reading input file')
62
- .default('i-read-opts', undefined, 'utf8') // will use node's default value
63
- .implies('i-read-opts', 'i')
64
-
65
- .option('i-glob-opts')
66
- .describe('i-glob-opts', 'Passed to fast-glob.sync when resolving glob patterns')
67
- .implies('i-glob-opts', 'i')
68
-
69
- .option('stdin')
70
- .describe('stdin', 'Wait for stdin input (should be set to false when used in non-interactive terminals)')
71
- .boolean('stdin')
72
- .default('stdin', true)
73
-
74
- .option('c', { demandOption: isContentPresent })
75
- .alias('c', 'content')
76
- .describe('c', 'Content to be replaced (takes precedence over stream & file input)')
77
- .string('c')
78
- .nargs('c', 1)
79
-
80
- .option('s')
81
- .alias('s', 'strategy')
82
- .describe('s', `output file generation strategy.
83
- \`join\` - join all input files and saves single file using "output" option as it's path,
84
- \`preserve-structure\` - when replacing files content copies them over to the directory specified by "output" option.
85
- \`flatten\` - same as \`preserve-structure\` but flattens the directory structure`)
86
- .nargs('s', 1)
87
- .choices('s', ['join', 'flatten', 'preserve-structure'])
88
- .default('s', 'join')
89
- .coerce('s', arg => arg.trim())
90
-
91
- .option('o')
92
- .alias('o', 'output')
93
- .describe('o', 'Output file name/path (replaces the file if it already exists and creates any intermediate directories if they don\'t already exist) or (when used together with `strategy` = `flatten` or `preserve-structure`) path to the output directory')
94
- .string('o')
95
- .nargs('o', 1)
96
-
97
- .option('o-write-opts')
98
- .describe('o-write-opts', 'Passed as options argument of write\'s .sync method')
99
- .default('o-write-opts', undefined, 'utf8') // will use node's default value
100
- .implies('o-write-opts', 'o')
101
-
102
- .option('o-join-str')
103
- .describe('o-join-str', 'String used when joining multiple files (use it together with either `output` or `stdout` option)')
104
- .default('o-join-str', undefined, 'newline (\\n)') // will use node's default value
105
-
106
- .option('stdout')
107
- .describe('stdout', 'Force sending output on stdout')
108
- .boolean('stdout')
109
- .default('stdout', isPiped, 'true when piped input present, false otherwise')
110
-
111
- .option('r')
112
- .alias('r', 'replace-fn')
113
- .describe('r', 'Treat replacement argument as path to file containing replacement function')
114
- .boolean('r')
115
-
116
- .help('h')
117
- .alias('h', 'help')
118
-
119
- .version('v')
120
- .alias('v', 'version')
121
-
122
- .epilog('Brought to you with open-source love by FRSource')
123
- .argv
124
-
125
- try {
126
- const result = replaceSync({
127
- input: argv.i,
128
- inputReadOptions: argv['i-read-opts'],
129
- inputGlobOptions: argv['i-glob-opts'],
130
- content: argv.c,
131
- strategy: argv.strategy,
132
- output: argv.o,
133
- outputWriteOptions: argv['o-write-opts'],
134
- outputJoinString: argv['o-join-str'],
135
- needle: new RegExp(argv.needle, argv.f),
136
- replacement: argv.r ? require(require('path').resolve(argv.replacement)) : argv.replacement
137
- })
138
-
139
- if (argv.stdout) {
140
- process.stdout.write(result[0][1])
141
- }
142
-
143
- return process.exit()
144
- } catch (e) /* istanbul ignore next */ {
145
- process.stderr.write(e.toString())
146
- return process.exit(1)
147
- }
148
- })
package/index.js DELETED
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- async: require('./src/async'),
3
- sync: require('./src/sync')
4
- }
package/src/async.js DELETED
@@ -1,104 +0,0 @@
1
- const write = require('write')
2
- const path = require('path')
3
- const fs = require('fs')
4
- const fastGlob = require('fast-glob')
5
- const { writeError, getReplaceFn } = require('./utils')
6
-
7
- const inputStrategyMap = {
8
- join: (results, outputJoinString) =>
9
- results.then(results => [
10
- Promise.all(results).then(results => {
11
- const len = results.length
12
- let result = (results[0] && results[0][1]) || ''
13
- for (let i = 1; i < len; ++i) {
14
- result += outputJoinString + results[i][1]
15
- }
16
- return ['', result]
17
- })
18
- ]),
19
- flatten: results =>
20
- results.then(results => results.map(async result => {
21
- result = await result
22
- result[0] = result[0].substring(result[0].lastIndexOf(path.sep))
23
- return result
24
- })),
25
- 'preserve-structure': results => results
26
- }
27
-
28
- const multipleFilesOutput = (results, output, outputWriteOptions) => {
29
- return results.then(results => results.map(
30
- async result => {
31
- result = await result
32
- result[0] = path.join(output, result[0])
33
- await write(result[0], result[1], outputWriteOptions)
34
- return result
35
- }
36
- ))
37
- }
38
-
39
- const outputStrategyMap = {
40
- join: (results, output, outputWriteOptions) =>
41
- results.then(results => [
42
- results[0].then(async result => {
43
- await write(output, result[1], outputWriteOptions)
44
- result[0] = output
45
- return result
46
- })
47
- ]),
48
- flatten: multipleFilesOutput,
49
- 'preserve-structure': multipleFilesOutput
50
- }
51
-
52
- module.exports = async ({
53
- input,
54
- inputReadOptions = 'utf8',
55
- inputGlobOptions,
56
- content,
57
- strategy = 'join',
58
- output,
59
- outputWriteOptions = 'utf8',
60
- outputJoinString = '\n',
61
- needle,
62
- replacement
63
- }) => {
64
- let results
65
- const replaceFn = getReplaceFn(needle, replacement)
66
-
67
- if (content !== undefined) {
68
- results = Promise.resolve([['', replaceFn(content)]])
69
- } else if (input !== undefined) {
70
- const fileStream = fastGlob.stream(input, inputGlobOptions)
71
- const replacePromises = []
72
-
73
- fileStream.on('error', writeError)
74
- fileStream.on('data', path => replacePromises.push(new Promise((resolve, reject) =>
75
- fs.readFile(path, inputReadOptions, (error, data) => {
76
- /* istanbul ignore next */
77
- if (error) return reject(error)
78
-
79
- resolve([path, replaceFn(data)])
80
- })
81
- )))
82
- results = new Promise(resolve =>
83
- fileStream.once('end', () =>
84
- resolve(replacePromises)
85
- )
86
- ).catch(writeError)
87
- } else {
88
- writeError('at least one input source must be defined!')
89
- }
90
-
91
- if (!inputStrategyMap[strategy]) writeError('unsupported strategy used! Possible values are: "join", "preserve-structure" or "flatten"')
92
- results = inputStrategyMap[strategy](results, outputJoinString)
93
-
94
- if (output !== undefined) {
95
- output = path.normalize(output)
96
- if (typeof outputWriteOptions === 'string') {
97
- outputWriteOptions = { encoding: outputWriteOptions }
98
- }
99
-
100
- results = outputStrategyMap[strategy](results, output, outputWriteOptions)
101
- }
102
-
103
- return results
104
- }
package/src/sync.js DELETED
@@ -1,88 +0,0 @@
1
- const write = require('write')
2
- const path = require('path')
3
- const fs = require('fs')
4
- const fastGlob = require('fast-glob')
5
-
6
- const { writeError, getReplaceFn } = require('./utils')
7
-
8
- const inputStrategyMap = {
9
- join: (results, len, outputJoinString) => {
10
- let result = (results[0] && results[0][1]) || ''
11
- for (let i = 1; i < len; ++i) {
12
- result += outputJoinString + results[i][1]
13
- }
14
- return [[['', result]], 1]
15
- },
16
- flatten: (results, len) => {
17
- for (let i = 0; i < len; ++i) {
18
- const result = results[i]
19
- result[0] = result[0].substring(result[0].lastIndexOf(path.sep))
20
- }
21
- return [results, len]
22
- },
23
- 'preserve-structure': (...args) => args
24
- }
25
-
26
- const multipleFilesOutputStrategy = (results, len, output, outputWriteOptions) => {
27
- for (let i = 0; i < len; ++i) {
28
- const result = results[i]
29
- result[0] = path.join(output, result[0])
30
- write.sync(result[0], result[1], outputWriteOptions)
31
- }
32
- return results
33
- }
34
-
35
- const outputStrategyMap = {
36
- join: (results, len, output, outputWriteOptions) => {
37
- write.sync(output, results[0][1], outputWriteOptions)
38
- results[0][0] = output
39
- return results
40
- },
41
- flatten: multipleFilesOutputStrategy,
42
- 'preserve-structure': multipleFilesOutputStrategy
43
- }
44
-
45
- module.exports = ({
46
- input,
47
- inputReadOptions = 'utf8',
48
- inputGlobOptions,
49
- content,
50
- strategy = 'join',
51
- output,
52
- outputWriteOptions = 'utf8',
53
- outputJoinString = '\n',
54
- needle,
55
- replacement
56
- }) => {
57
- let results
58
- const replaceFn = getReplaceFn(needle, replacement)
59
-
60
- if (content !== undefined) {
61
- results = [['', replaceFn(content)]]
62
- } else if (input !== undefined) {
63
- results = []
64
- const files = fastGlob.sync(input, inputGlobOptions)
65
- const len = files.length
66
- for (let i = 0; i < len; ++i) {
67
- const filePath = files[i]
68
- results.push([filePath, replaceFn(fs.readFileSync(filePath, inputReadOptions))])
69
- }
70
- } else {
71
- writeError('at least one input source must be defined!')
72
- }
73
-
74
- let len
75
- if (!inputStrategyMap[strategy]) writeError('unsupported strategy used! Possible values are: "join", "preserve-structure" or "flatten"');
76
- [results, len] = inputStrategyMap[strategy](results, results.length, outputJoinString)
77
-
78
- if (output !== undefined) {
79
- output = path.normalize(output)
80
- if (typeof outputWriteOptions === 'string') {
81
- outputWriteOptions = { encoding: outputWriteOptions }
82
- }
83
-
84
- results = outputStrategyMap[strategy](results, len, output, outputWriteOptions)
85
- }
86
-
87
- return results
88
- }
package/src/utils.js DELETED
@@ -1,22 +0,0 @@
1
- const writeError = msg => { throw new Error(`@frsource/frs-replace :: ${msg}`) }
2
-
3
- const getReplaceFn = (needle, replacement) =>
4
- typeof needle === 'string'
5
- ? content => {
6
- const needleLen = needle.length
7
- let result = ''
8
- let i
9
- let endIndex = 0
10
-
11
- while ((i = content.indexOf(needle, endIndex)) !== -1) {
12
- result += content.slice(endIndex, i) + replacement
13
- endIndex = i + needleLen
14
- }
15
-
16
- result += content.slice(endIndex, content.length)
17
-
18
- return result
19
- }
20
- : content => content.replace(needle, replacement)
21
-
22
- module.exports = { writeError, getReplaceFn }
package/sync.js DELETED
@@ -1 +0,0 @@
1
- module.exports = require('./src/sync')