diff --git a/packages/cli/README.md b/packages/cli/README.md index c9220af6..b64b0b42 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -81,13 +81,15 @@ ARGUMENTS PATTERN [default: **/*.{js,jsx,ts,tsx}] file pattern to scan for strings OPTIONS - -v, --verbose verbose output - --cds-host=cds-host CDS host URL - --dry-run dry run, do not push to Transifex - --purge purge content on Transifex - --secret=secret native project secret - --tags=tags globally tag strings - --token=token native project public token + -v, --verbose verbose output + --append-tags=append-tags append tags to strings + --cds-host=cds-host CDS host URL + --dry-run dry run, do not push to Transifex + --purge purge content on Transifex + --secret=secret native project secret + --token=token native project public token + --with-tags-only=with-tags-only push strings with specific tags + --without-tags-only=without-tags-only push strings without specific tags DESCRIPTION Parse .js, .ts, .jsx and .tsx files and detect phrases marked for @@ -109,7 +111,9 @@ DESCRIPTION txjs-cli push /home/repo/src txjs-cli push "*.js" txjs-cli push --dry-run - txjs-cli push --tags="master,release:2.5" + txjs-cli push --append-tags="master,release:2.5" + txjs-cli push --with-tags-only="home,error" + txjs-cli push --without-tags-only="custom" txjs-cli push --token=mytoken --secret=mysecret TRANSIFEX_TOKEN=mytoken TRANSIFEX_SECRET=mysecret txjs-cli push ``` diff --git a/packages/cli/src/api/extract.js b/packages/cli/src/api/extract.js index 96f75496..61b8dc74 100644 --- a/packages/cli/src/api/extract.js +++ b/packages/cli/src/api/extract.js @@ -19,7 +19,7 @@ const { stringToArray, mergeArrays } = require('./utils'); * @param {Number} params._charlimit * @param {Number} params._tags * @param {String} occurence - * @param {String[]} globalTags + * @param {String[]} appendTags * @returns {Object} Payload * @returns {String} Payload.string * @returns {String} Payload.key @@ -29,7 +29,7 @@ const { stringToArray, mergeArrays } = require('./utils'); * @returns {String[]} Payload.meta.tags * @returns {String[]} Payload.meta.occurrences */ -function createPayload(string, params, occurence, globalTags) { +function createPayload(string, params, occurence, appendTags) { return { string, key: generateKey(string, params), @@ -37,12 +37,36 @@ function createPayload(string, params, occurence, globalTags) { context: stringToArray(params._context), developer_comment: params._comment, character_limit: params._charlimit ? parseInt(params._charlimit, 10) : undefined, - tags: mergeArrays(stringToArray(params._tags), globalTags), + tags: mergeArrays(stringToArray(params._tags), appendTags), occurrences: [occurence], }, _.isNil), }; } +/** + * Check if payload coming from createPayload is valid based on tag filters + * + * @param {Object} payload + * @param {String[]} options.filterWithTags + * @param {String[]} options.filterWithoutTags + * @returns {Boolean} + */ +function isPayloadValid(payload, options = {}) { + const { filterWithTags, filterWithoutTags } = options; + let isValid = true; + _.each(filterWithTags, (tag) => { + if (!_.includes(payload.meta.tags, tag)) { + isValid = false; + } + }); + _.each(filterWithoutTags, (tag) => { + if (_.includes(payload.meta.tags, tag)) { + isValid = false; + } + }); + return isValid; +} + /** * Check if callee is a valid Transifex Native function * @@ -92,10 +116,14 @@ function _parse(source) { * * @param {String} file absolute file path * @param {String} relativeFile occurence - * @param {String[]} globalTags + * @param {Object} options + * @param {String[]} options.appendTags + * @param {String[]} options.filterWithTags + * @param {String[]} options.filterWithoutTags * @returns {Object} */ -function extractPhrases(file, relativeFile, globalTags) { +function extractPhrases(file, relativeFile, options = {}) { + const { appendTags } = options; const HASHES = {}; const source = fs.readFileSync(file, 'utf8'); const ast = _parse(source); @@ -124,7 +152,9 @@ function extractPhrases(file, relativeFile, globalTags) { }); } - const partial = createPayload(string, params, relativeFile, globalTags); + const partial = createPayload(string, params, relativeFile, appendTags); + if (!isPayloadValid(partial, options)) return; + mergePayload(HASHES, { [partial.key]: { string: partial.string, @@ -156,7 +186,10 @@ function extractPhrases(file, relativeFile, globalTags) { }); if (!string) return; - const partial = createPayload(string, params, relativeFile, globalTags); + + const partial = createPayload(string, params, relativeFile, appendTags); + if (!isPayloadValid(partial, options)) return; + mergePayload(HASHES, { [partial.key]: { string: partial.string, diff --git a/packages/cli/src/commands/push.js b/packages/cli/src/commands/push.js index 1e1e27dd..d73d699f 100644 --- a/packages/cli/src/commands/push.js +++ b/packages/cli/src/commands/push.js @@ -40,7 +40,9 @@ class PushCommand extends Command { filePattern = path.join(filePattern, '**/*.{js,jsx,ts,tsx}'); } - const globalTags = stringToArray(flags.tags); + const appendTags = stringToArray(flags['append-tags']); + const filterWithTags = stringToArray(flags['with-tags-only']); + const filterWithoutTags = stringToArray(flags['without-tags-only']); this.log('Parsing all files to detect translatable content...'); @@ -64,11 +66,17 @@ class PushCommand extends Command { }); bar.start(allFiles.length, 0); + const extractOptions = { + appendTags, + filterWithTags, + filterWithoutTags, + }; + _.each(allFiles, (file) => { const relativeFile = file.replace(pwd, ''); bar.increment({ file: relativeFile.gray }); try { - const data = extractPhrases(file, relativeFile, globalTags); + const data = extractPhrases(file, relativeFile, extractOptions); tree[relativeFile] = data; if (_.isEmpty(data)) { emptyFiles += 1; @@ -190,7 +198,9 @@ txjs-cli push src/ txjs-cli push /home/repo/src txjs-cli push "*.js" txjs-cli push --dry-run -txjs-cli push --tags="master,release:2.5" +txjs-cli push --append-tags="master,release:2.5" +txjs-cli push --with-tags-only="home,error" +txjs-cli push --without-tags-only="custom" txjs-cli push --token=mytoken --secret=mysecret TRANSIFEX_TOKEN=mytoken TRANSIFEX_SECRET=mysecret txjs-cli push `; @@ -224,8 +234,16 @@ PushCommand.flags = { description: 'native project secret', default: '', }), - tags: flags.string({ - description: 'globally tag strings', + 'append-tags': flags.string({ + description: 'append tags to strings', + default: '', + }), + 'with-tags-only': flags.string({ + description: 'push strings with specific tags', + default: '', + }), + 'without-tags-only': flags.string({ + description: 'push strings without specific tags', default: '', }), 'cds-host': flags.string({ diff --git a/packages/cli/test/api/extract.test.js b/packages/cli/test/api/extract.test.js index 37bc50fa..f93aa492 100644 --- a/packages/cli/test/api/extract.test.js +++ b/packages/cli/test/api/extract.test.js @@ -32,8 +32,8 @@ describe('extractPhrases', () => { }); }); - it('works with global tags', async () => { - expect(await extractPhrases('test/fixtures/webpack.js', 'webpack.js', ['g1', 'g2'])) + it('works with append tags', async () => { + expect(await extractPhrases('test/fixtures/webpack.js', 'webpack.js', { appendTags: ['g1', 'g2'] })) .to.deep.equal({ '6f48100ca5a57d2db9b685a8373be8a6': { string: 'Text 1', diff --git a/packages/cli/test/commands/push.test.js b/packages/cli/test/commands/push.test.js index b618760a..59804dae 100644 --- a/packages/cli/test/commands/push.test.js +++ b/packages/cli/test/commands/push.test.js @@ -42,6 +42,32 @@ describe('push command', () => { expect(ctx.stdout).to.not.contain('f2138b2131e064313c369b20006549df: Text 1'); }); + test + .stdout() + .command(['push', 'test/fixtures/tags.js', '--dry-run', '-v', '--append-tags=custom']) + .it('append tags', (ctx) => { + expect(ctx.stdout).to.contain('tags: ["tag1","tag2","custom"]'); + expect(ctx.stdout).to.contain('tags: ["tag2","tag3","custom"]'); + expect(ctx.stdout).to.contain('tags: ["custom"]'); + }); + + test + .stdout() + .command(['push', 'test/fixtures/tags.js', '--dry-run', '-v', '--with-tags-only=tag1']) + .it('filters-in tags', (ctx) => { + expect(ctx.stdout).to.not.contain('tag3'); + expect(ctx.stdout).to.contain('tag1'); + }); + + test + .stdout() + .command(['push', 'test/fixtures/tags.js', '--dry-run', '-v', '--without-tags-only=tag1']) + .it('filters-out tags', (ctx) => { + expect(ctx.stdout).to.contain('tag2'); + expect(ctx.stdout).to.contain('tag3'); + expect(ctx.stdout).to.not.contain('tag1'); + }); + test .nock('https://cds.svc.transifex.net', (api) => api .post('/content') diff --git a/packages/cli/test/fixtures/tags.js b/packages/cli/test/fixtures/tags.js new file mode 100644 index 00000000..30136758 --- /dev/null +++ b/packages/cli/test/fixtures/tags.js @@ -0,0 +1,5 @@ +import { t } from '@transifex/native'; + +t('Text 1', { _tags: 'tag1,tag2' }); +t('Text 2', { _tags: 'tag2,tag3' }); +t('Text 3');