i18next-parser
Advanced tools
Comparing version 1.0.0-beta28 to 1.0.0-beta29
@@ -5,5 +5,5 @@ # Contribute | ||
1. If you are unsure, open a ticket before working on anything | ||
1. If you are unsure, open a ticket before working on anything. | ||
2. Fork and clone the project | ||
3. Create a branch `git checkout -b feature/my-feature` (or `hotfix`) | ||
3. Create a branch `git checkout -b feature/my-feature` (or `hotfix`). If you want to work on multiple bugs or improvements, do so in multiple branches and PRs. It almost always complicated things to mix unrelated changes. | ||
4. Push the code to your fork | ||
@@ -10,0 +10,0 @@ 5. **Write tests and documentation. I won't merge a PR without it!** |
@@ -5,3 +5,3 @@ { | ||
"name": "i18next-parser", | ||
"version": "1.0.0-beta28", | ||
"version": "1.0.0-beta29", | ||
"license": "MIT", | ||
@@ -22,6 +22,2 @@ "main": "dist/index.js", | ||
"acorn": "^5.5.3", | ||
"acorn-es7": "^0.1.0", | ||
"acorn-jsx": "^4.1.1", | ||
"acorn-object-rest-spread": "^1.1.0", | ||
"acorn-stage3": "^0.6.0", | ||
"broccoli-plugin": "^1.3.0", | ||
@@ -46,2 +42,5 @@ "cheerio": "^1.0.0-rc.2", | ||
"devDependencies": { | ||
"acorn-es7": "^0.1.0", | ||
"acorn-jsx": "^4.1.1", | ||
"acorn-stage3": "^0.6.0", | ||
"babel-cli": "^6.26.0", | ||
@@ -58,2 +57,3 @@ "babel-plugin-add-module-exports": "^0.2.1", | ||
"mocha": "^5.0.0", | ||
"sinon": "^6.2.0", | ||
"typescript": "^3.0.3" | ||
@@ -60,0 +60,0 @@ }, |
136
README.md
@@ -190,19 +190,54 @@ # i18next Parser [![Build Status](https://travis-ci.org/i18next/i18next-parser.svg?branch=master)](https://travis-ci.org/i18next/i18next-parser) | ||
Note the presence of a `default` which will catch any extension that is not listed. There are 3 lexers available: `HandlebarsLexer`, `HTMLLexer` and `JavascriptLexer`. Each has configurations of its own. If you need to change the defaults, you can do it like so: | ||
Note the presence of a `default` which will catch any extension that is not listed. | ||
There are 5 lexers available: `HandlebarsLexer`, `HTMLLexer`, `JavascriptLexer`, | ||
`JsxLexer`, and `TypescriptLexer`. Each has configurations of its own. | ||
If you need to change the defaults, you can do it like so: | ||
```js | ||
[ | ||
// HandlebarsLexer default config (hbs, handlebars) | ||
handlebars: [{ | ||
lexer: 'HandlebarsLexer', | ||
functions: ['t'] // Array of functions to match | ||
}] | ||
#### Javascript | ||
The Javascript lexer uses [Acorn](https://github.com/acornjs/acorn) to walk through your code and extract references | ||
translation functions. If your code uses features not supported natively by Acorn, you can enable support through | ||
`injectors` and `plugins` configuration. Note that you must install these additional dependencies yourself through | ||
`yarn` or `npm`; they are not included in this package. This is an example configuration that adds all non-jsx plugins supported by acorn | ||
at the time of writing: | ||
```javascript | ||
const injectAcornStaticClassPropertyInitializer = require('acorn-static-class-property-initializer/inject'); | ||
const injectAcornStage3 = require('acorn-stage3/inject'); | ||
const injectAcornEs7 = require('acorn-es7'); | ||
// HtmlLexer default config (htm, html) | ||
html: [{ | ||
lexer: 'HtmlLexer', | ||
attr: 'data-i18n' // Attribute for the keys | ||
optionAttr: 'data-i18n-options' // Attribute for the options | ||
}] | ||
// ... | ||
js: [{ | ||
lexer: 'JavascriptLexer' | ||
functions: ['t'], // Array of functions to match | ||
// acorn config (for more information on the acorn options, see here: https://github.com/acornjs/acorn#main-parser) | ||
acorn: { | ||
injectors: [ | ||
injectAcornStaticClassPropertyInitializer, | ||
injectAcornStage3, | ||
injectAcornEs7, | ||
], | ||
plugins: { | ||
// The presence of these plugin options is important - | ||
// without them, the plugins will be available but not | ||
// enabled. | ||
staticClassPropertyInitializer: true, | ||
stage3: true, | ||
es7: true, | ||
} | ||
} | ||
}], | ||
// ... | ||
``` | ||
If you receive an error that looks like this: | ||
```bash | ||
TypeError: baseVisitor[type] is not a function | ||
# rest of stack trace... | ||
``` | ||
The problem is likely that you are missing a plugin that supports a feature that your code uses. | ||
The default configuration is below: | ||
```js | ||
{ | ||
// JavascriptLexer default config (js, mjs) | ||
@@ -217,9 +252,21 @@ js: [{ | ||
ecmaVersion: 9, // forward compatibility | ||
plugins: { | ||
es7: true, // some es7 parsing that's not yet in acorn (decorators) | ||
stage3: true // load some stage3 configs not yet in a version | ||
} | ||
// Allows additional acorn plugins via the exported injector functions | ||
injectors: [], | ||
plugins: {}, | ||
} | ||
}], | ||
} | ||
``` | ||
#### Jsx | ||
The JSX lexer builds off of the Javascript lexer, and additionally requires the `acorn-jsx` plugin. To use it, add `acorn-jsx` to your dev dependencies: | ||
```bash | ||
npm install -D acorn-jsx | ||
# or | ||
yarn add -D acorn-jsx | ||
``` | ||
Default configuration: | ||
```js | ||
{ | ||
// JsxLexer default config (jsx) | ||
@@ -235,10 +282,20 @@ // JsxLexer can take all the options of the JavascriptLexer plus the following | ||
ecmaVersion: 9, // forward compatibility | ||
plugins: { | ||
es7: true, // some es7 parsing that's not yet in acorn (decorators) | ||
stage3: true, // load some stage3 configs not yet in a version | ||
jsx: true // always defaults to true in .jsx files | ||
} | ||
injectors: [], | ||
plugins: {}, | ||
} | ||
}], | ||
} | ||
``` | ||
#### Ts(x) | ||
The Typescript lexer builds off of the JSX lexer, and additionally requires Typescript. To use it, add both `typescript` and `acorn-jsx` to your dev dependencies: | ||
```bash | ||
npm install -D typescript acorn-jsx | ||
# or | ||
yarn add -D typescript acorn-jsx | ||
``` | ||
If you need additional plugins, you can install them in the same way as described in the Javascript lexer configuration. | ||
Default configuration: | ||
```js | ||
{ | ||
// TypescriptLexer default config (ts/x) | ||
@@ -257,16 +314,27 @@ // TypescriptLexer can take all the options of the JsxLexer in addition to | ||
}, | ||
}] | ||
} | ||
``` | ||
// acorn config (for more information on the acorn options, see here: https://github.com/acornjs/acorn#main-parser) | ||
acorn: { | ||
sourceType: 'module', | ||
ecmaVersion: 9, // forward compatibility | ||
plugins: { | ||
es7: true, // some es7 parsing that's not yet in acorn (decorators) | ||
stage3: true, // load some stage3 configs not yet in a version | ||
jsx: true // always defaults to true in .jsx files | ||
} | ||
} | ||
#### Handlebars | ||
```js | ||
{ | ||
// HandlebarsLexer default config (hbs, handlebars) | ||
handlebars: [{ | ||
lexer: 'HandlebarsLexer', | ||
functions: ['t'] // Array of functions to match | ||
}] | ||
] | ||
} | ||
``` | ||
#### Html | ||
```js | ||
{ | ||
// HtmlLexer default config (htm, html) | ||
html: [{ | ||
lexer: 'HtmlLexer', | ||
attr: 'data-i18n' // Attribute for the keys | ||
optionAttr: 'data-i18n-options' // Attribute for the options | ||
}] | ||
} | ||
``` | ||
@@ -273,0 +341,0 @@ ## Events |
import * as acorn from 'acorn' | ||
import injectAcornStage3 from "acorn-stage3/inject" | ||
import injectAcornEs7 from "acorn-es7" | ||
import * as walk from 'acorn/dist/walk' | ||
@@ -17,11 +15,8 @@ import BaseLexer from './base-lexer' | ||
this.acornOptions = { | ||
sourceType: 'module', | ||
this.acornOptions = { | ||
sourceType: 'module', | ||
ecmaVersion: 9, | ||
injectors: [], | ||
plugins: {}, | ||
...options.acorn, | ||
plugins: { | ||
stage3: true, | ||
es7: true, | ||
...(options.acorn ? options.acorn.plugins : {}) | ||
} | ||
} | ||
@@ -35,10 +30,7 @@ | ||
if (this.acornOptions.plugins) { | ||
if (this.acornOptions.plugins.stage3) { | ||
this.acorn = injectAcornStage3(this.acorn) | ||
} | ||
if (this.acornOptions.plugins.es7) { | ||
injectAcornEs7(this.acorn) | ||
} | ||
} | ||
// Apply all injectors to the acorn instance | ||
this.acornOptions.injectors.reduce( | ||
(acornInstance, injector) => injector(acornInstance), | ||
this.acorn | ||
) | ||
} | ||
@@ -45,0 +37,0 @@ |
import JavascriptLexer from './javascript-lexer' | ||
import * as walk from 'acorn/dist/walk' | ||
import injectAcornJsx from 'acorn-jsx/inject' | ||
@@ -39,3 +38,11 @@ const JSXParserExtension = { | ||
this.acorn = injectAcornJsx(this.acorn) | ||
try { | ||
const injectAcornJsx = require('acorn-jsx/inject') | ||
this.acorn = injectAcornJsx(this.acorn) | ||
} catch (e) { | ||
throw new Error( | ||
'You must install acorn-jsx to parse jsx files. ' + | ||
'Try running "yarn add acorn-jsx" or "npm install acorn-jsx"' | ||
) | ||
} | ||
} | ||
@@ -42,0 +49,0 @@ |
@@ -5,18 +5,2 @@ import JsxLexer from './jsx-lexer' | ||
let loadedTs = null | ||
function loadTypeScript() { | ||
if (loadedTs) { | ||
return loadedTs | ||
} | ||
try { | ||
loadedTs = require('typescript') | ||
} catch (e) { | ||
throw new ParsingError(`You must install typescript to parse TypeScript files. ` | ||
+ `Try running "yarn add typescript" or "npm install typescript"`) | ||
} | ||
return loadedTs | ||
} | ||
export default class TypescriptLexer extends JsxLexer { | ||
@@ -26,6 +10,14 @@ constructor(options = {}) { | ||
this.tsOptions = options.tsOptions | ||
try { | ||
this.typescript = require('typescript') | ||
} catch (e) { | ||
throw new Error( | ||
'You must install typescript to parse TypeScript files. ' + | ||
'Try running "yarn add typescript" or "npm install typescript"' | ||
) | ||
} | ||
} | ||
extract(content, extension) { | ||
const transpiled = loadTypeScript().transpileModule(content, { | ||
const transpiled = this.typescript.transpileModule(content, { | ||
compilerOptions: { | ||
@@ -32,0 +24,0 @@ ...this.tsOptions, |
@@ -1,2 +0,6 @@ | ||
import { assert } from 'chai' | ||
import { assert, expect } from 'chai' | ||
import { spy } from 'sinon' | ||
import stage3Injector from 'acorn-stage3/inject' | ||
import es7Injector from 'acorn-es7' | ||
import JavascriptLexer from '../../src/lexers/javascript-lexer' | ||
@@ -95,5 +99,5 @@ | ||
it('supports the acorn-es7 plugin', (done) => { | ||
const Lexer = new JavascriptLexer({ acorn: { plugins: { es7: true } } }) | ||
const content = '@decorator() class Test { test() { t("foo") } }' | ||
it('supports the spread operator in objects plugin', (done) => { | ||
const Lexer = new JavascriptLexer({ acorn: { ecmaVersion: 9 } }) | ||
const content = 'const data = { text: t("foo"), ...rest }; const { text, ...more } = data;' | ||
assert.deepEqual(Lexer.extract(content), [ | ||
@@ -105,5 +109,18 @@ { key: 'foo' } | ||
it('supports the spread operator in objects plugin', (done) => { | ||
const Lexer = new JavascriptLexer({ acorn: { ecmaVersion: 9 } }) | ||
const content = 'const data = { text: t("foo"), ...rest }; const { text, ...more } = data;' | ||
it('supports dynamic imports with acorn-stage3 plugin', (done) => { | ||
const Lexer = new JavascriptLexer({ | ||
acorn: { | ||
ecmaVersion: 6, | ||
injectors: [stage3Injector], | ||
plugins: { stage3: true } | ||
} | ||
}) | ||
const content = 'import("path/to/some/file").then(doSomethingWithData)' | ||
Lexer.extract(content) | ||
done() | ||
}) | ||
it('supports the acorn-es7 plugin', (done) => { | ||
const Lexer = new JavascriptLexer({ acorn: { injectors: [es7Injector], plugins: { es7: true } } }) | ||
const content = '@decorator() class Test { test() { t("foo") } }' | ||
assert.deepEqual(Lexer.extract(content), [ | ||
@@ -115,12 +132,10 @@ { key: 'foo' } | ||
describe('supports the acorn-stage3 plugin', () => { | ||
it('supports dynamic imports', (done) => { | ||
const Lexer = new JavascriptLexer({ acorn: { ecmaVersion: 6, plugins: { stage3: true } } }) | ||
const content = 'import("path/to/some/file").then(doSomethingWithData)' | ||
Lexer.extract(content) | ||
describe('supports additional plugins via injector option', () => { | ||
it('calls provided injectors with acorn', (done) => { | ||
const injector = spy(acorn => acorn) | ||
const Lexer = new JavascriptLexer({ acorn: { ecmaVersion: 6, injectors: [injector] } }) | ||
expect(injector.calledOnce).to.be.true | ||
done() | ||
}) | ||
}) | ||
}) |
@@ -1,2 +0,3 @@ | ||
import { assert } from 'chai' | ||
import { assert, expect } from 'chai' | ||
import { spy } from 'sinon' | ||
import JsxLexer from '../../src/lexers/jsx-lexer' | ||
@@ -106,2 +107,10 @@ | ||
}) | ||
describe('supports additional plugins via injector option', () => { | ||
it('provided injectors are called with acorn', (done) => { | ||
const injector = spy(acorn => acorn) | ||
const Lexer = new JsxLexer({ acorn: { ecmaVersion: 6, injectors: [injector] } }) | ||
expect(injector.calledOnce).to.be.true | ||
done() | ||
}) | ||
}) | ||
}) |
import { assert } from 'chai' | ||
import stage3Injector from 'acorn-stage3/inject' | ||
import es7Injector from 'acorn-es7' | ||
import TypescriptLexer from '../../src/lexers/typescript-lexer' | ||
@@ -210,5 +213,5 @@ | ||
it('supports the acorn-es7 plugin', (done) => { | ||
const Lexer = new TypescriptLexer({ acorn: { plugins: { es7: true } } }) | ||
const content = '@decorator() class Test { test() { t("foo") } }' | ||
it('supports the spread operator in objects plugin', (done) => { | ||
const Lexer = new TypescriptLexer({ acorn: { ecmaVersion: 9 } }) | ||
const content = 'const data = { text: t("foo"), ...rest }; const { text, ...more } = data;' | ||
assert.deepEqual(Lexer.extract(content), [ | ||
@@ -220,5 +223,5 @@ { key: 'foo' } | ||
it('supports the spread operator in objects plugin', (done) => { | ||
const Lexer = new TypescriptLexer({ acorn: { ecmaVersion: 9 } }) | ||
const content = 'const data = { text: t("foo"), ...rest }; const { text, ...more } = data;' | ||
it('supports the acorn-es7 plugin', (done) => { | ||
const Lexer = new TypescriptLexer({ acorn: { injectors: [es7Injector], plugins: { es7: true } } }) | ||
const content = '@decorator() class Test { test() { t("foo") } }' | ||
assert.deepEqual(Lexer.extract(content), [ | ||
@@ -230,12 +233,8 @@ { key: 'foo' } | ||
describe('supports the acorn-stage3 plugin', () => { | ||
it('supports dynamic imports', (done) => { | ||
const Lexer = new TypescriptLexer({ acorn: { ecmaVersion: 6, plugins: { stage3: true } } }) | ||
const content = 'import("path/to/some/file").then(doSomethingWithData)' | ||
Lexer.extract(content) | ||
done() | ||
}) | ||
it('supports dynamic imports with acorn-stage3 plugin', (done) => { | ||
const Lexer = new TypescriptLexer({ acorn: { ecmaVersion: 6, injectors: [stage3Injector], plugins: { stage3: true } } }) | ||
const content = 'import("path/to/some/file").then(doSomethingWithData)' | ||
Lexer.extract(content) | ||
done() | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
480237
14
4046
376
16
- Removedacorn-es7@^0.1.0
- Removedacorn-jsx@^4.1.1
- Removedacorn-object-rest-spread@^1.1.0
- Removedacorn-stage3@^0.6.0
- Removedacorn@2.7.0(transitive)
- Removedacorn-bigint@0.2.0(transitive)
- Removedacorn-class-fields@0.1.2(transitive)
- Removedacorn-dynamic-import@3.0.0(transitive)
- Removedacorn-es7@0.1.0(transitive)
- Removedacorn-import-meta@0.2.1(transitive)
- Removedacorn-json-superset@0.1.1(transitive)
- Removedacorn-jsx@4.1.1(transitive)
- Removedacorn-numeric-separator@0.1.1(transitive)
- Removedacorn-object-rest-spread@1.1.0(transitive)
- Removedacorn-optional-catch-binding@0.1.1(transitive)
- Removedacorn-private-methods@0.1.1(transitive)
- Removedacorn-stage3@0.6.0(transitive)