diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..b107111 --- /dev/null +++ b/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": [ + ["@babel/preset-env", { + "targets": { + "browsers":[ + "defaults" + ] + } + }, "@babel/react"] + ] +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..edb4aba --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +# EditorConfig is awesome: http://EditorConfig.org +root = true + +[*.{js,jsx,json,ts}] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..2a77c65 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +/dist +# /types +/examples \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..26399d6 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,21 @@ +{ + "extends": [ + "standard", + "plugin:require-path-exists/recommended" + ], + "plugins": [ + "require-path-exists" + ], + "globals": { + "describe": false, + "it": false, + "before": false, + "after": false, + "beforeEach": false, + "afterEach": false + }, + "rules": { + "array-bracket-spacing": 0, + "standard/no-callback-literal": 0 + } +} \ No newline at end of file diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..e1fa181 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,23 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 7 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - "discussion" + - "feature request" + - "bug" + - "breaking change" + - "doc" + - "issue" + - "help wanted" + - "good first issue" +# Label to use when marking an issue as stale +staleLabel: stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml new file mode 100644 index 0000000..4c33775 --- /dev/null +++ b/.github/workflows/node.yml @@ -0,0 +1,24 @@ +name: node + +on: + push: + branches: + - main + +jobs: + test: + name: Test on node ${{ matrix.node }} and ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + node: [ '20.x', '18.x', '16.x' ] + # os: [ubuntu-latest, windows-latest, macOS-latest] + os: [ubuntu-latest] + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node }} + - run: npm install + - run: npm test \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..25b4ef2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +node_modules +.DS_Store +npm-debug.log +package-lock.json +dist +# types +# !dist/ +# dist/* +# !dist/deno/ \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..ff19cdb --- /dev/null +++ b/.npmignore @@ -0,0 +1,11 @@ +.DS_Store +.eslintrc +.gitignore +.npmignore +.editorconfig +.vscode +README.md +.eslintignore +test +scripts +examples \ No newline at end of file diff --git a/.ts.eslintrc b/.ts.eslintrc new file mode 100644 index 0000000..72db1d0 --- /dev/null +++ b/.ts.eslintrc @@ -0,0 +1,37 @@ +{ + "extends": [ + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "env": { "node": true }, + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "project": "./tsconfig.json", + "createDefaultProgram": true + }, + "rules": { + "semi": ["error", "never"], + "import/export": "off", // this errors on multiple exports (overload interfaces) + "require-path-exists/exists": "off" + }, + "overrides": [ + { + "files": ["*.d.ts","*.test-d.ts"], + "rules": { + "@typescript-eslint/no-explicit-any": "off" + } + }, + { + "files": ["*.test-d.ts"], + "rules": { + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-non-null-assertion": "off" + } + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8859237 --- /dev/null +++ b/README.md @@ -0,0 +1,142 @@ +# Introduction + +[![Actions](https://github.com/i18next/i18next-resources-for-ts/workflows/node/badge.svg)](https://github.com/i18next/i18next-resources-for-ts/actions?query=workflow%3Anode) +[![npm version](https://img.shields.io/npm/v/i18next-resources-for-ts.svg?style=flat-square)](https://www.npmjs.com/package/i18next-resources-for-ts) + +This package helps to transform resources to be used in a typesafe i18next project. + +# Getting started + +Source can be loaded via [npm](https://www.npmjs.com/package/i18next-resources-for-ts). + +```bash +# npm package +$ npm install i18next-resources-for-ts +``` + +## Usage via code (toc): + +```js +import { tocForResources } from 'i18next-resources-for-ts' + +const nsA = { + name: 'nsA', + path: '/some/path/locales/en/nsA.json' +} +const nsB = { + name: 'nsB', + path: '/some/path/locales/en/nsB.json' +} + +const toc = tocForResources([nsA, nsB], '/some/path') +// import nsA from './locales/en/nsA.json'; +// import nsB from './locales/en/nsB.json'; + +// export default { +// nsA, +// nsB +// } +``` + +## Usage via code (merge): + +```js +import { mergeResources } from 'i18next-resources-for-ts' + +const nsA = { + name: 'nsA', + path: '/some/path/locales/en/nsA.json', + resources: { + k1: 'v1', + k2: 'v2', + k3: { + d3: 'v3' + } + } +} +const nsB = { + name: 'nsB', + path: '/some/path/locales/en/nsB.json', + resources: { + k21: 'v21', + k22: 'v22', + k23: { + d23: 'v23' + } + } +} + +const merged = mergeResources([nsA, nsB]) +// { +// nsA: { +// k1: 'v1', +// k2: 'v2', +// k3: { +// d3: 'v3' +// } +// }, +// nsB: { +// k21: 'v21', +// k22: 'v22', +// k23: { +// d23: 'v23' +// } +// } +// } +``` + +Usage via CLI: + +```sh +# use it with npx +npx i18next-resources-for-ts subcommand -i /Users/user/my/input -o /Users/user/my/output + +# or install it globally +npm install i18next-resources-for-ts -g + +# subcommand is either toc or merge +# -i is the input path +# -o is the output path +# if the output path is not provided, it will use the input path as base path for the result file + +i18next-resources-for-ts toc -i /Users/user/my/input -o /Users/user/my/output.ts +i18next-resources-for-ts merge -i /Users/user/my/input -o /Users/user/my/output.json +# i18next-resources-for-ts toc /Users/user/my/input -o /Users/user/my/output +# i18next-resources-for-ts toc -o /Users/user/my/output +# i18next-resources-for-ts toc -i /Users/user/my/input +# i18next-resources-for-ts toc +``` + +*Make sure your folder structure contains all relevant namespaces (in your source/reference language):* + +```sh +└── namespace.json +``` + +i.e. +```sh +├── translation.json +└── common.json +``` + +--- + +

Gold Sponsors

+ +

+ + + +

+ +--- + +**From the creators of i18next: localization as a service - locize.com** + +A translation management system built around the i18next ecosystem - [locize.com](https://locize.com). + +![locize](https://locize.com/img/ads/github_locize.png) + +With using [locize](http://locize.com/?utm_source=react_i18next_readme&utm_medium=github) you directly support the future of i18next. + +--- diff --git a/bin/getNamespaces.js b/bin/getNamespaces.js new file mode 100755 index 0000000..cc52965 --- /dev/null +++ b/bin/getNamespaces.js @@ -0,0 +1,40 @@ +const fs = require('fs') +const path = require('path') + +const getFiles = (srcpath) => { + return fs.readdirSync(srcpath).filter((file) => { + return !fs.statSync(path.join(srcpath, file)).isDirectory() + }).filter((file) => path.extname(file) === '.json').map((file) => path.join(srcpath, file)) +} + +const getDirectories = (srcpath) => { + return fs.readdirSync(srcpath).filter((file) => { + return fs.statSync(path.join(srcpath, file)).isDirectory() + }).map((dir) => path.join(srcpath, dir)) +} + +function getAllFiles (srcpath) { + let files = getFiles(srcpath) + const dirs = getDirectories(srcpath) + dirs.forEach((dir) => { + files = files.concat(getAllFiles(dir)) + }) + return files +} + +module.exports = (p) => { + const allFiles = getAllFiles(p) + + return allFiles.map((file) => { + const namespace = JSON.parse(fs.readFileSync(file, 'utf-8')) + const sepFile = file.split(path.sep) + const fileName = sepFile[sepFile.length - 1] + const name = path.parse(fileName).name + + return { + name, + path: file, + resources: namespace + } + }) +} diff --git a/bin/i18next-resources-for-ts.js b/bin/i18next-resources-for-ts.js new file mode 100755 index 0000000..84f087a --- /dev/null +++ b/bin/i18next-resources-for-ts.js @@ -0,0 +1,56 @@ +#!/usr/bin/env node + +const fs = require('fs') +const path = require('path') +const getNamespaces = require('./getNamespaces.js') +const { + tocForResources, + mergeResources +} = require('../') + +const cliArgs = process.argv.slice(2) + +const subCommands = [ + 'toc', + 'merge' +] + +if (cliArgs.length === 0 || subCommands.indexOf(cliArgs[0]) < 0) { + throw new Error(`Please define an appropriate subcommand: ${subCommands.join(', ')}!`) +} + +const subCommand = cliArgs[0] + +let inputPath = process.cwd() +let outputPath = inputPath +if (cliArgs.length > 0 && cliArgs[1].indexOf('-') !== 0) { + inputPath = cliArgs[1] + outputPath = inputPath +} + +const inputArgIndex = cliArgs.indexOf('-i') +const outputArgIndex = cliArgs.indexOf('-o') +if (inputArgIndex > -1 && cliArgs[inputArgIndex + 1]) inputPath = cliArgs[inputArgIndex + 1] +if (outputArgIndex > -1 && cliArgs[outputArgIndex + 1]) outputPath = cliArgs[outputArgIndex + 1] + +const namespaces = getNamespaces(inputPath) + +if (subCommand === 'toc') { + let outputFile = outputPath + if (!outputFile.endsWith('.ts')) { + outputFile = path.join(outputFile, 'resources.ts') + } + const toc = tocForResources(namespaces, outputFile) + fs.writeFileSync(outputFile, toc, 'utf-8') + console.log(`created toc resources file for ${namespaces.length} namespaces: ${outputFile}`) +} + +if (subCommand === 'merge') { + const merged = mergeResources(namespaces) + let outputFile = outputPath + if (!outputFile.endsWith('.json')) { + outputFile = path.join(outputFile, 'resources.json') + } + fs.writeFileSync(outputFile, JSON.stringify(merged, null, 2), 'utf-8') + console.log(`created merged resources file for ${namespaces.length} namespaces: ${outputFile}`) +} diff --git a/bin/package.json b/bin/package.json new file mode 100644 index 0000000..729ac4d --- /dev/null +++ b/bin/package.json @@ -0,0 +1 @@ +{"type":"commonjs"} diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..b20cbdd --- /dev/null +++ b/index.d.ts @@ -0,0 +1,23 @@ +export type Resources = { + [key: string]: any +} + +export type NamespaceForToc = { + name: string; + path: string; + resources?: Resources; +} +export type NamespacesForToc = NamespaceForToc[] + +export type NamespaceForMerge = { + name: string; + path?: string; + resources: Resources; +} +export type NamespacesForMerge = NamespaceForMerge[] +export type Merged = { + [ns: string]: Resources; +} + +export function tocForResources (namespaces: NamespacesForToc, toPath: string, options?: { quotes?: 'single' | 'double' }): string +export function mergeResources (namespaces: NamespacesForMerge): Merged diff --git a/index.js b/index.js new file mode 100644 index 0000000..28ea284 --- /dev/null +++ b/index.js @@ -0,0 +1,9 @@ +import { + tocForResources, + mergeResources +} from './src/index.js' + +export { + tocForResources, + mergeResources +} diff --git a/licence b/licence new file mode 100644 index 0000000..d520788 --- /dev/null +++ b/licence @@ -0,0 +1,19 @@ +Copyright (c) 2023 i18next + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/package.json b/package.json new file mode 100644 index 0000000..9043a12 --- /dev/null +++ b/package.json @@ -0,0 +1,95 @@ +{ + "name": "i18next-resources-for-ts", + "version": "1.0.0", + "description": "This package helps to transform resources to be used in a typesafe i18next project.", + "keywords": [ + "i18next", + "typescript" + ], + "homepage": "https://github.com/i18next/i18next-resources-for-ts", + "repository": { + "type": "git", + "url": "git@github.com:i18next/i18next-resources-for-ts.git" + }, + "bugs": { + "url": "https://github.com/i18next/i18next-resources-for-ts/issues" + }, + "type": "module", + "main": "./dist/cjs/index.js", + "module": "./dist/esm/index.js", + "browser": "./dist/umd/i18nextResourcesForTS.js", + "types": "./index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "types": { + "require": "./dist/cjs/index.d.ts", + "import": "./dist/esm/index.d.ts" + }, + "module": "./dist/esm/index.js", + "import": "./dist/esm/index.js", + "require": "./dist/cjs/index.js", + "default": "./dist/esm/index.js" + }, + "./cjs": { + "types": "./dist/cjs/index.d.ts", + "default": "./dist/cjs/index.js" + }, + "./esm": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "./src": { + "default": "./src/index.js" + } + }, + "bin": { + "i18next-resources-for-ts": "./bin/i18next-resources-for-ts.js" + }, + "scripts": { + "lint:javascript": "eslint .", + "lint:typescript": "eslint -c .ts.eslintrc *.d.ts test/types/**/*.test-d.ts", + "lint": "npm run lint:javascript && npm run lint:typescript", + "build": "rm -rf dist && rollup -c && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json && cp index.d.ts dist/cjs/index.d.ts && cp index.d.ts dist/esm/index.d.ts", + "test:typescript": "tsd", + "test": "npm run lint && mocha --colors --reporter spec --recursive test/*.js", + "test:all": "npm run test && npm run test:typescript", + "preversion": "npm run test && npm run build && git push", + "postversion": "git push && git push --tags" + }, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.22.5" + }, + "devDependencies": { + "@babel/core": "^7.22.5", + "@babel/plugin-transform-runtime": "^7.22.5", + "@babel/preset-env": "^7.22.5", + "@types/mocha": "^10.0.1", + "@typescript-eslint/eslint-plugin": "^5.59.9", + "@typescript-eslint/parser": "^5.59.9", + "babel-plugin-add-module-exports": "^1.0.4", + "eslint": "^8.42.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^15.7.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-require-path-exists": "^1.1.9", + "eslint-plugin-standard": "^5.0.0", + "i18next": "^22.5.1", + "i18next-chained-backend": "^4.3.0", + "mocha": "^10.2.0", + "rollup": "^2.79.1", + "@rollup/plugin-babel": "^6.0.3", + "@rollup/plugin-commonjs": "^25.0.1", + "@rollup/plugin-node-resolve": "^15.1.0", + "rollup-plugin-terser": "^7.0.2", + "should": "^13.2.3", + "sinon": "^15.1.0", + "tsd": "^0.28.1", + "typescript": "^5.1.3" + }, + "tsd": { + "directory": "test/types" + } +} diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..66c3b8c --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,82 @@ +import { babel } from '@rollup/plugin-babel' +import { nodeResolve } from '@rollup/plugin-node-resolve' +import { terser } from 'rollup-plugin-terser' +import commonjs from '@rollup/plugin-commonjs' +import pkg from './package.json' + +const getBabelOptions = ({ useESModules, plugins = [] }) => ({ + exclude: /node_modules/, + babelHelpers: 'runtime', + plugins: [['@babel/transform-runtime', { useESModules }]].concat(plugins), + comments: false +}) + +const input = './src/index.js' +// check relative and absolute paths for windows and unix +const external = id => !id.startsWith('.') && !id.startsWith('/') && !id.includes(':') + +export default [ + { + input, + output: { + dir: 'dist/cjs', + preserveModules: true, + // file: pkg.main, + format: 'cjs' + }, + external, + // external: [ + // ...Object.keys(pkg.dependencies || {}) + // ], + plugins: [babel(getBabelOptions({ + useESModules: false, + plugins: [['add-module-exports']] + }))] + }, + { + input, + output: { + dir: 'dist/esm', + preserveModules: true, + // file: pkg.module, + format: 'esm' // the preferred format + }, + external, + // external: [ + // ...Object.keys(pkg.dependencies || {}) + // ], + plugins: [babel(getBabelOptions({ useESModules: true }))] + }, + // this is not used, if we make sure every js file is imported with .js ending + // { + // input, + // output: { + // dir: 'dist/deno', + // preserveModules: true, + // // file: pkg.module, + // format: 'esm' // the preferred format + // }, + // external + // // external: [ + // // ...Object.keys(pkg.dependencies || {}) + // // ] + // }, + { + input, + output: { + file: pkg.browser, + format: 'umd', + name: 'i18nextResourcesForTS' // the global which can be used in a browser + }, + plugins: [commonjs(), babel(getBabelOptions({ useESModules: true })), nodeResolve()] + }, + { + input, + output: { + file: pkg.browser.replace('.js', '.min.js'), + format: 'umd', + name: 'i18nextResourcesForTS' // the global which can be used in a browser + }, + plugins: [commonjs(), babel(getBabelOptions({ useESModules: true })), nodeResolve(), terser()] + } +] diff --git a/src/defaults.js b/src/defaults.js new file mode 100644 index 0000000..85c7e1b --- /dev/null +++ b/src/defaults.js @@ -0,0 +1,5 @@ +const defaults = { + quotes: 'single' +} + +export default defaults diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..0aea10e --- /dev/null +++ b/src/index.js @@ -0,0 +1,7 @@ +import tocForResources from './tocForResources.js' +import mergeResources from './mergeResources.js' + +export { + tocForResources, + mergeResources +} diff --git a/src/mergeResources.js b/src/mergeResources.js new file mode 100644 index 0000000..7d59624 --- /dev/null +++ b/src/mergeResources.js @@ -0,0 +1,8 @@ +function mergeResources (namespaces) { + return namespaces.reduce((prev, cur) => { + prev[cur.name] = cur.resources + return prev + }, {}) +} + +export default mergeResources diff --git a/src/relative.js b/src/relative.js new file mode 100644 index 0000000..3fa942c --- /dev/null +++ b/src/relative.js @@ -0,0 +1,60 @@ +function trim (arr, startOnly) { + let start = 0 + for (; start < arr.length; start++) { + if (arr[start] !== '') break + } + + let end = arr.length - 1 + for (; end >= 0; end--) { + if (arr[end] !== '') break + } + + if (start > end) return [] + if (startOnly) return arr.slice(start) + return arr.slice(start, end - start + 1) +} + +const pathSeparatorWin = '\\' +const pathSeparator = '/' + +function relative (from, to) { + let separator = pathSeparator + if (from.indexOf(pathSeparatorWin) > 0 || to.indexOf(pathSeparatorWin) > 0) { + separator = pathSeparatorWin + } + + if (from.endsWith(separator)) from = from.substring(0, from.length - separator.length) + + const toParts = trim(to.split(separator), true) + + const lowerFromParts = trim(from.split(separator), from.indexOf('.') < 0) + const lowerToParts = trim(to.split(separator), true) + + const length = Math.min(lowerFromParts.length, lowerToParts.length) + let samePartsLength = length + + for (let i = 0; i < length; i++) { + if (lowerFromParts[i] !== lowerToParts[i]) { + samePartsLength = i + break + } + } + + if (samePartsLength === 0) return to + + let outputParts = [] + for (let i = samePartsLength; i < lowerFromParts.length; i++) { + outputParts.push('..') + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)) + + let ret = outputParts.join(separator) + if (!ret.startsWith(from.substring(0, 2)) && !ret.startsWith('.')) { + ret = `.${pathSeparator}${ret}` + } + + return ret +} + +export default relative diff --git a/src/tocForResources.js b/src/tocForResources.js new file mode 100644 index 0000000..38b0026 --- /dev/null +++ b/src/tocForResources.js @@ -0,0 +1,26 @@ +import defaults from './defaults.js' +import relative from './relative.js' + +function tocForResources (namespaces, toPath, options = {}) { + const opt = { ...options, ...defaults } + const quoteChar = opt.quotes === 'single' ? '\'' : '"' + + let toc = '' + + namespaces.forEach((ns) => { + toc += `import ${ns.name} from ${quoteChar}${relative(toPath, ns.path)}${quoteChar};\n` + }) + + toc += '\nexport default {' + namespaces.forEach((ns, i) => { + toc += `\n ${ns.name}` + if (i < namespaces.length - 1) { + toc += ',' + } + }) + toc += '\n}\n' + + return toc +} + +export default tocForResources diff --git a/test/basic.spec.js b/test/basic.spec.js new file mode 100644 index 0000000..ec7df37 --- /dev/null +++ b/test/basic.spec.js @@ -0,0 +1,55 @@ +import { + tocForResources, + mergeResources +} from '../index.js' +import should from 'should' + +const nsA = { + name: 'nsA', + path: '/some/path/locales/en/nsA.json', + resources: { + k1: 'v1', + k2: 'v2', + k3: { + d3: 'v3' + } + } +} +const nsB = { + name: 'nsB', + path: '/some/path/locales/en/nsB.json', + resources: { + k21: 'v21', + k22: 'v22', + k23: { + d23: 'v23' + } + } +} + +const allMerged = { nsA: nsA.resources, nsB: nsB.resources } + +const toc = `import nsA from './locales/en/nsA.json'; +import nsB from './locales/en/nsB.json'; + +export default { + nsA, + nsB +} +` + +describe('tocForResources', () => { + it('should generate a toc file content from namespace resources', async () => { + const tocRet = tocForResources([nsA, nsB], '/some/path') + // console.log(tocRet) + should(tocRet).eql(toc) + }) +}) + +describe('mergeResources', () => { + it('should generate a big json from namespace resources', async () => { + const merged = mergeResources([nsA, nsB]) + // console.log(merged) + should(merged).eql(allMerged) + }) +}) diff --git a/test/types/basic.test-d.ts b/test/types/basic.test-d.ts new file mode 100644 index 0000000..26f661f --- /dev/null +++ b/test/types/basic.test-d.ts @@ -0,0 +1,9 @@ +import { + tocForResources, + mergeResources, + Merged +} from '../../' +import { expectType } from 'tsd' + +expectType(tocForResources([{ name: 'ns1', path: '/some/path' }], '/some')) +expectType(mergeResources([{ name: 'ns1', resources: { key: 'val' } }])) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..0b29b93 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es6", + "lib": [ "es2015" ], + "module": "commonjs", + "noEmit": true, + "strict": true + }, + "include": [ + "/test/types/*.test-d.ts", + "/*.d.ts" + ] +}