From fc3ef89f49fc2486dcb55d30e0527709a09d71fa Mon Sep 17 00:00:00 2001 From: Enrico Bottacin Date: Wed, 7 Aug 2019 11:24:35 +0200 Subject: [PATCH 1/9] * add IoC layer using InverfiyJS * add preprocessKey method to parserInterface * refcator cli.ts to load parser and compilers impls with IoC --- package-lock.json | 10 ++ package.json | 2 + src/cli/cli.ts | 33 ++++--- src/compilers/abstract-compiler.ts | 20 ++++ src/compilers/compiler.factory.ts | 17 ++-- src/compilers/compiler.interface.ts | 5 + src/compilers/custom.compiler.ts | 24 +++++ src/compilers/json.compiler.ts | 14 +-- src/compilers/namespaced-json.compiler.ts | 14 +-- src/compilers/po.compiler.ts | 10 +- src/index.ts | 2 + src/ioc/inversify.config.parsers.kml.ts | 27 ++++++ src/ioc/inversify.config.ts | 97 +++++++++++++++++++ src/ioc/types.ts | 11 +++ src/parsers/abstract-ast.parser.ts | 5 +- src/parsers/abstract-preprocess.parser.ts | 11 +++ src/parsers/directive.parser.ts | 16 ++- src/parsers/function.parser.ts | 28 ++++-- src/parsers/parser.interface.ts | 19 ++++ src/parsers/pipe.parser.ts | 18 +++- src/parsers/service.parser.ts | 12 ++- .../namespaced-json.compiler.spec.ts | 3 + tests/parsers/directive.parser.spec.ts | 3 + tests/parsers/function.parser.spec.ts | 3 + tests/parsers/pipe.parser.spec.ts | 3 + tests/parsers/service.parser.spec.ts | 3 + tsconfig.json | 3 + 27 files changed, 356 insertions(+), 57 deletions(-) create mode 100644 src/compilers/abstract-compiler.ts create mode 100644 src/compilers/custom.compiler.ts create mode 100644 src/ioc/inversify.config.parsers.kml.ts create mode 100644 src/ioc/inversify.config.ts create mode 100644 src/ioc/types.ts create mode 100644 src/parsers/abstract-preprocess.parser.ts diff --git a/package-lock.json b/package-lock.json index c1c304db..892937ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -627,6 +627,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "inversify": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.1.tgz", + "integrity": "sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==" + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", @@ -1079,6 +1084,11 @@ "util-deprecate": "^1.0.1" } }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", diff --git a/package.json b/package.json index 13ab4391..da1b486b 100644 --- a/package.json +++ b/package.json @@ -63,8 +63,10 @@ "flat": "git://github.com/lenchvolodymyr/flat.git#ffe77ef", "gettext-parser": "^4.0.1", "glob": "^7.1.4", + "inversify": "^5.0.1", "mkdirp": "^0.5.1", "path": "^0.12.7", + "reflect-metadata": "^0.1.13", "terminal-link": "^1.3.0", "typescript": "^3.5.3", "yargs": "^13.3.0" diff --git a/src/cli/cli.ts b/src/cli/cli.ts index a0cd694b..c6077575 100755 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -2,11 +2,8 @@ import * as fs from 'fs'; import * as yargs from 'yargs'; import { ExtractTask } from './tasks/extract.task'; -import { ParserInterface } from '../parsers/parser.interface'; -import { PipeParser } from '../parsers/pipe.parser'; -import { DirectiveParser } from '../parsers/directive.parser'; -import { ServiceParser } from '../parsers/service.parser'; -import { FunctionParser } from '../parsers/function.parser'; +import { ParserInterface, ParserInterfaceWithConfig } from '../parsers/parser.interface'; + import { PostProcessorInterface } from '../post-processors/post-processor.interface'; import { SortByKeyPostProcessor } from '../post-processors/sort-by-key.post-processor'; import { KeyAsDefaultValuePostProcessor } from '../post-processors/key-as-default-value.post-processor'; @@ -15,6 +12,10 @@ import { CompilerInterface } from '../compilers/compiler.interface'; import { CompilerFactory } from '../compilers/compiler.factory'; import { donateMessage } from '../utils/donate'; +import { interfaces } from 'inversify'; +import TYPES from '../ioc/types'; +import container from '../ioc/inversify.config'; + export const cli = yargs .usage('Extract strings from files for translation.\nUsage: $0 [options]') .version(require(__dirname + '/../../package.json').version) @@ -61,7 +62,7 @@ export const cli = yargs describe: 'Output format', default: 'json', type: 'string', - choices: ['json', 'namespaced-json', 'pot'] + choices: ['json', 'namespaced-json', 'pot', 'custom'] }) .option('format-indentation', { alias: 'fi', @@ -96,21 +97,23 @@ export const cli = yargs .exitProcess(true) .parse(process.argv); -const extractTask = new ExtractTask(cli.input, cli.output, { +export const extractTask = new ExtractTask(cli.input, cli.output, { replace: cli.replace, patterns: cli.patterns }); // Parsers -const parsers: ParserInterface[] = [ - new PipeParser(), - new DirectiveParser(), - new ServiceParser() -]; +const parsers: ParserInterface[] = [container.get(TYPES.ServiceParser), + container.get(TYPES.DirectiveParser), + container.get(TYPES.PipeParser)]; + + if (cli.marker) { - parsers.push(new FunctionParser({ + let functionParserFactory = container.get>(TYPES.ParserWithConfigFactory); + let functionParser = functionParserFactory({ identifier: cli.marker - })); + }); + parsers.push( functionParser); } extractTask.setParsers(parsers); @@ -133,6 +136,6 @@ const compiler: CompilerInterface = CompilerFactory.create(cli.format, { }); extractTask.setCompiler(compiler); -extractTask.execute(); +//extractTask.execute(); console.log(donateMessage); diff --git a/src/compilers/abstract-compiler.ts b/src/compilers/abstract-compiler.ts new file mode 100644 index 00000000..e4dc0d6c --- /dev/null +++ b/src/compilers/abstract-compiler.ts @@ -0,0 +1,20 @@ +import { injectable } from 'inversify'; + +@injectable() +export abstract class AbstractCompiler { + + public indentation: string = '\t'; + + set config(options: any) { + if (options && typeof options.indentation !== 'undefined') { + this.indentation = options.indentation; + } + } + + get config() { + return {indentation: this.indentation}; + } + + constructor() {} + +} diff --git a/src/compilers/compiler.factory.ts b/src/compilers/compiler.factory.ts index eb9870b6..00fd0079 100644 --- a/src/compilers/compiler.factory.ts +++ b/src/compilers/compiler.factory.ts @@ -1,17 +1,14 @@ import { CompilerInterface } from '../compilers/compiler.interface'; -import { JsonCompiler } from '../compilers/json.compiler'; -import { NamespacedJsonCompiler } from '../compilers/namespaced-json.compiler'; -import { PoCompiler } from '../compilers/po.compiler'; +import container from '../ioc/inversify.config'; +import TYPES from '../ioc/types'; +import { interfaces } from 'inversify'; export class CompilerFactory { - public static create(format: string, options?: {}): CompilerInterface { - switch (format) { - case 'pot': return new PoCompiler(options); - case 'json': return new JsonCompiler(options); - case 'namespaced-json': return new NamespacedJsonCompiler(options); - default: throw new Error(`Unknown format: ${format}`); - } + public static create(format: string, options?: any): CompilerInterface { + let compilerFactory = container.get>(TYPES.CompilerFactory); + let compiler = compilerFactory(format, options); + return compiler as CompilerInterface; } } diff --git a/src/compilers/compiler.interface.ts b/src/compilers/compiler.interface.ts index 83b0575f..44a09eff 100644 --- a/src/compilers/compiler.interface.ts +++ b/src/compilers/compiler.interface.ts @@ -1,9 +1,14 @@ import { TranslationCollection } from '../utils/translation.collection'; +import { Options } from 'yargs-parser'; export interface CompilerInterface { + config: Options; + extension: string; + selector: string; + compile(collection: TranslationCollection): string; parse(contents: string): TranslationCollection; diff --git a/src/compilers/custom.compiler.ts b/src/compilers/custom.compiler.ts new file mode 100644 index 00000000..26caeefb --- /dev/null +++ b/src/compilers/custom.compiler.ts @@ -0,0 +1,24 @@ + +import { TranslationCollection } from '../utils/translation.collection'; +import { injectable } from 'inversify'; +import { CompilerInterface } from './compiler.interface'; +import { AbstractCompiler } from './abstract-compiler'; + +@injectable() +export class CustomCompiler extends AbstractCompiler implements CompilerInterface { + + public extension: string = 'xml'; + public selector: string = 'custom'; + constructor () { + super(); + } + + public compile(collection: TranslationCollection): string { + throw new Error('not implemented'); + } + + public parse(contents: string): TranslationCollection { + throw new Error('not implemented'); + } + +} diff --git a/src/compilers/json.compiler.ts b/src/compilers/json.compiler.ts index 08e72f13..55ab6ff1 100644 --- a/src/compilers/json.compiler.ts +++ b/src/compilers/json.compiler.ts @@ -4,16 +4,18 @@ import { stripBOM } from '../utils/utils'; import { flatten } from 'flat'; -export class JsonCompiler implements CompilerInterface { +import { injectable } from 'inversify'; +import { AbstractCompiler } from './abstract-compiler'; - public indentation: string = '\t'; +@injectable() +export class JsonCompiler extends AbstractCompiler implements CompilerInterface { + + public selector: string = 'json'; public extension: string = 'json'; - public constructor(options?: any) { - if (options && typeof options.indentation !== 'undefined') { - this.indentation = options.indentation; - } + public constructor() { + super(); } public compile(collection: TranslationCollection): string { diff --git a/src/compilers/namespaced-json.compiler.ts b/src/compilers/namespaced-json.compiler.ts index c0e341b6..9021a701 100644 --- a/src/compilers/namespaced-json.compiler.ts +++ b/src/compilers/namespaced-json.compiler.ts @@ -3,17 +3,17 @@ import { TranslationCollection } from '../utils/translation.collection'; import { stripBOM } from '../utils/utils'; import { flatten, unflatten } from 'flat'; +import { injectable } from 'inversify'; +import { AbstractCompiler } from './abstract-compiler'; -export class NamespacedJsonCompiler implements CompilerInterface { - - public indentation: string = '\t'; +@injectable() +export class NamespacedJsonCompiler extends AbstractCompiler implements CompilerInterface { public extension = 'json'; + public selector = 'namespaced-json'; - public constructor(options?: any) { - if (options && typeof options.indentation !== 'undefined') { - this.indentation = options.indentation; - } + public constructor() { + super(); } public compile(collection: TranslationCollection): string { diff --git a/src/compilers/po.compiler.ts b/src/compilers/po.compiler.ts index a6ffa318..1b374bb2 100644 --- a/src/compilers/po.compiler.ts +++ b/src/compilers/po.compiler.ts @@ -2,17 +2,23 @@ import { CompilerInterface } from './compiler.interface'; import { TranslationCollection, TranslationType } from '../utils/translation.collection'; import * as gettext from 'gettext-parser'; +import { injectable } from 'inversify'; +import { AbstractCompiler } from './abstract-compiler'; -export class PoCompiler implements CompilerInterface { +@injectable() +export class PoCompiler extends AbstractCompiler implements CompilerInterface { public extension: string = 'po'; + public selector: string = 'pot'; /** * Translation domain */ public domain: string = ''; - public constructor(options?: any) {} + public constructor() { + super(); + } public compile(collection: TranslationCollection): string { const data = { diff --git a/src/index.ts b/src/index.ts index 34bc206e..032edb4c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,8 @@ export * from './utils/translation.collection'; export * from './utils/utils'; +export * from './ioc/types'; + export * from './cli/cli'; export * from './cli/tasks/task.interface'; export * from './cli/tasks/extract.task'; diff --git a/src/ioc/inversify.config.parsers.kml.ts b/src/ioc/inversify.config.parsers.kml.ts new file mode 100644 index 00000000..d91beb9d --- /dev/null +++ b/src/ioc/inversify.config.parsers.kml.ts @@ -0,0 +1,27 @@ +import TYPES from './types'; +import { Container } from 'inversify'; + +import { KmlServiceParser } from '../custom-parsers/kml.service.parser'; +import { KmlDirectiveParser } from '../custom-parsers/kml.directive.parser'; +import { KmlPipeParser } from '../custom-parsers/kml.pipe.parser'; +import { KmlFunctionParser } from '../custom-parsers/kml.function.parser'; + + +import { setupParsers, IoCParserConfig, IoCCompilerConfig, setupCompilers } from './inversify.config'; +import { KmlCustomCompiler } from '../custom-compilers/kml-custom.compiler'; + +const parsersConfig: IoCParserConfig = { + parsers: [{type: TYPES.ServiceParser, obj: KmlServiceParser}, + {type: TYPES.DirectiveParser, obj: KmlDirectiveParser}, + {type: TYPES.PipeParser, obj: KmlPipeParser} + ], + parsersWithConfig: [{type: TYPES.FunctionParser, obj: KmlFunctionParser}] +}; + +const compilersConfig: IoCCompilerConfig = { + compilers: [KmlCustomCompiler] +}; + +export const configCompilers = (container: Container) => { setupCompilers(container, compilersConfig); }; + +export const configParsers = (container: Container) => { setupParsers(container, parsersConfig); }; diff --git a/src/ioc/inversify.config.ts b/src/ioc/inversify.config.ts new file mode 100644 index 00000000..ce5a1c61 --- /dev/null +++ b/src/ioc/inversify.config.ts @@ -0,0 +1,97 @@ +import { Container, interfaces } from 'inversify'; +import TYPES from './types'; +import { ParserInterface, ParserInterfaceWithConfig } from '../parsers/parser.interface'; +import { ServiceParser } from '../parsers/service.parser'; +import { DirectiveParser } from '../parsers/directive.parser'; +import { PipeParser } from '../parsers/pipe.parser'; +import { FunctionParser } from '../parsers/function.parser'; +import { CompilerInterface } from '../compilers/compiler.interface'; +import { JsonCompiler } from '../compilers/json.compiler'; +import { PoCompiler } from '../compilers/po.compiler'; +import { NamespacedJsonCompiler } from '../compilers/namespaced-json.compiler'; +import { CustomCompiler } from '../compilers/custom.compiler'; + + +const container = new Container(); + +export interface IoCParserConfig { + parsers: {type: symbol, obj: interfaces.Newable}[]; + parsersWithConfig: {type: symbol, obj: interfaces.Newable}[]; +} + +export interface IoCCompilerConfig { + compilers: interfaces.Newable[] +} + +export const setupParsers = (container: Container, parserConfig: IoCParserConfig ) => { + parserConfig.parsers.forEach( (item) => { + if (container.isBound(item.type)) { + container.unbind(item.type); + } + container.bind(item.type).to(item.obj); + }); + parserConfig.parsersWithConfig.forEach( item => { + if (container.isBound(item.type)) { + container.unbind(item.type); + } + container.bind(item.type).to(item.obj); + }); +}; + +export const configFactories = (container: Container) => { + container.bind>(TYPES.ParserWithConfigFactory).toFactory( (context: interfaces.Context) => { + return (config: any) => { + let parserInterfaceWithConfig = context.container.get(TYPES.FunctionParser); + parserInterfaceWithConfig.config = config; + return parserInterfaceWithConfig; + }; + }); + container.bind>(TYPES.CompilerFactory).toFactory( (context: interfaces.Context) => { + return (format: string, config: any) => { + let compiler = context.container.getNamed(TYPES.Compiler, format); + compiler.config = config; + return compiler; + }; + }); +}; + +export const setupCompilers = (container: Container, compilersConfig?: IoCCompilerConfig) => { + // container.unbind for named is not implemented yet + // as workaround unbind all classes and rebind compilerConfig first then add default compilers if not + // already binded + if (container.isBound(TYPES.Compiler)) { + container.unbind(TYPES.Compiler); + } + + if (compilersConfig !== undefined) { + compilersConfig.compilers.forEach( (compiler) => { + let selector: string = new compiler().selector; + container.bind(TYPES.Compiler).to(compiler).whenTargetNamed(selector); + }); + } + + defaultCompilersConfig.compilers.forEach( (compiler) => { + let selector: string = new compiler().selector; + if (!container.isBoundNamed(TYPES.Compiler,selector)) { + container.bind(TYPES.Compiler).to(compiler).whenTargetNamed(selector); + } + }); +}; + +const defaultCompilersConfig: IoCCompilerConfig = { + compilers: [JsonCompiler, NamespacedJsonCompiler, PoCompiler, CustomCompiler] +}; + +const parsersConfig: IoCParserConfig = { + parsers: [{type: TYPES.ServiceParser, obj: ServiceParser}, + {type: TYPES.DirectiveParser, obj: DirectiveParser}, + {type: TYPES.PipeParser, obj: PipeParser} + ], + parsersWithConfig: [{type: TYPES.FunctionParser, obj: FunctionParser}] +}; + +setupParsers(container, parsersConfig); +setupCompilers(container); +configFactories(container); + +export default container; diff --git a/src/ioc/types.ts b/src/ioc/types.ts new file mode 100644 index 00000000..b9c07efc --- /dev/null +++ b/src/ioc/types.ts @@ -0,0 +1,11 @@ +let TYPES = { + DirectiveParser: Symbol('ParserInterface'), + ServiceParser: Symbol('ParserInterface'), + PipeParser: Symbol('ParserInterface'), + FunctionParser: Symbol('ParserInterface'), + Compiler: Symbol('CompilerInterface'), + ParserWithConfigFactory: Symbol('Factory'), + CompilerFactory: Symbol('Factory') +}; + +export default TYPES; diff --git a/src/parsers/abstract-ast.parser.ts b/src/parsers/abstract-ast.parser.ts index 7cfee3d0..067309c7 100644 --- a/src/parsers/abstract-ast.parser.ts +++ b/src/parsers/abstract-ast.parser.ts @@ -6,8 +6,11 @@ import { SyntaxKind, StringLiteral } from 'typescript'; +import { AbstractPreprocessParser } from './abstract-preprocess.parser'; +import { injectable } from 'inversify'; -export abstract class AbstractAstParser { +@injectable() +export abstract class AbstractAstParser extends AbstractPreprocessParser { protected sourceFile: SourceFile; diff --git a/src/parsers/abstract-preprocess.parser.ts b/src/parsers/abstract-preprocess.parser.ts new file mode 100644 index 00000000..2a91193f --- /dev/null +++ b/src/parsers/abstract-preprocess.parser.ts @@ -0,0 +1,11 @@ +import { KeysPreprocessContextInterface } from './parser.interface'; +import { injectable } from 'inversify'; + +@injectable() +export abstract class AbstractPreprocessParser { + + public preprocessKeys(keys: string[], context: KeysPreprocessContextInterface): string[] { + return keys; + } + +} diff --git a/src/parsers/directive.parser.ts b/src/parsers/directive.parser.ts index 7b7032de..fd8ffc92 100644 --- a/src/parsers/directive.parser.ts +++ b/src/parsers/directive.parser.ts @@ -1,10 +1,13 @@ -import { ParserInterface } from './parser.interface'; +import { ParserInterface, KeysPreprocessContextInterface } from './parser.interface'; +import { AbstractPreprocessParser } from './abstract-preprocess.parser'; import { TranslationCollection } from '../utils/translation.collection'; import { isPathAngularComponent, extractComponentInlineTemplate } from '../utils/utils'; import { parseTemplate, TmplAstNode, TmplAstElement, TmplAstTextAttribute } from '@angular/compiler'; +import { injectable } from 'inversify'; -export class DirectiveParser implements ParserInterface { +@injectable() +export class DirectiveParser extends AbstractPreprocessParser implements ParserInterface { public extract(template: string, path: string): TranslationCollection { if (path && isPathAngularComponent(path)) { @@ -16,7 +19,14 @@ export class DirectiveParser implements ParserInterface { const nodes: TmplAstNode[] = this.parseTemplate(template, path); this.getTranslatableElements(nodes).forEach(element => { const key = this.getElementTranslateAttrValue(element) || this.getElementContents(element); - collection = collection.add(key); + let preprocessCtx: KeysPreprocessContextInterface = { + template: template, + path: path, + ctxObj: { + tmlAstElement: element + } + }; + collection = collection.add(this.preprocessKeys([key], preprocessCtx)[0]); }); return collection; diff --git a/src/parsers/function.parser.ts b/src/parsers/function.parser.ts index e1db7a7d..f3ddc3df 100644 --- a/src/parsers/function.parser.ts +++ b/src/parsers/function.parser.ts @@ -1,20 +1,27 @@ import { Node, CallExpression, SyntaxKind, Identifier } from 'typescript'; -import { ParserInterface } from './parser.interface'; +import { KeysPreprocessContextInterface, ParserInterfaceWithConfig } from './parser.interface'; import { AbstractAstParser } from './abstract-ast.parser'; import { TranslationCollection } from '../utils/translation.collection'; +import { injectable } from 'inversify'; -export class FunctionParser extends AbstractAstParser implements ParserInterface { +@injectable() +export class FunctionParser extends AbstractAstParser implements ParserInterfaceWithConfig { protected functionIdentifier: string = 'marker'; - public constructor(options?: any) { - super(); - if (options && typeof options.identifier !== 'undefined') { - this.functionIdentifier = options.identifier; + set config (opt: any) { + if (opt && typeof opt.identifier !== 'undefined') { + this.functionIdentifier = opt.identifier; } } + get config() { + return { + identfier: this.functionIdentifier + }; + } + public extract(template: string, path: string): TranslationCollection { let collection: TranslationCollection = new TranslationCollection(); @@ -24,7 +31,14 @@ export class FunctionParser extends AbstractAstParser implements ParserInterface callNodes.forEach(callNode => { const keys: string[] = this.getStringLiterals(callNode); if (keys && keys.length) { - collection = collection.addKeys(keys); + let preprocessCtx: KeysPreprocessContextInterface = { + template: template, + path: path, + ctxObj: { + callExpression: callNode + } + }; + collection = collection.addKeys(this.preprocessKeys(keys, preprocessCtx)); } }); return collection; diff --git a/src/parsers/parser.interface.ts b/src/parsers/parser.interface.ts index bc395d0e..0b0ec925 100644 --- a/src/parsers/parser.interface.ts +++ b/src/parsers/parser.interface.ts @@ -1,7 +1,26 @@ import { TranslationCollection } from '../utils/translation.collection'; +import { CallExpression, ClassDeclaration, SourceFile } from 'typescript'; +import { TmplAstElement } from '@angular/compiler'; + +export interface KeysPreprocessContextInterface { + template: string; + path: string; + ctxObj?: { + sourceFile?: SourceFile, + classDeclaration?: ClassDeclaration, + propertyName?: string, + callExpression?: CallExpression, + tmlAstElement?: TmplAstElement + }; +} export interface ParserInterface { extract(template: string, path: string): TranslationCollection; + preprocessKeys(key: string[], context: KeysPreprocessContextInterface): string[]; +} + +export interface ParserInterfaceWithConfig extends ParserInterface { + config: any } diff --git a/src/parsers/pipe.parser.ts b/src/parsers/pipe.parser.ts index 4666012d..c25041a2 100644 --- a/src/parsers/pipe.parser.ts +++ b/src/parsers/pipe.parser.ts @@ -1,24 +1,32 @@ -import { ParserInterface } from './parser.interface'; +import { ParserInterface, KeysPreprocessContextInterface } from './parser.interface'; +import { AbstractPreprocessParser } from './abstract-preprocess.parser'; import { TranslationCollection } from '../utils/translation.collection'; import { isPathAngularComponent, extractComponentInlineTemplate } from '../utils/utils'; +import { injectable } from 'inversify'; -export class PipeParser implements ParserInterface { +@injectable() +export class PipeParser extends AbstractPreprocessParser implements ParserInterface { public extract(template: string, path: string): TranslationCollection { if (path && isPathAngularComponent(path)) { template = extractComponentInlineTemplate(template); } - return this.parseTemplate(template); + return this.parseTemplate(template, path); } - protected parseTemplate(template: string): TranslationCollection { + protected parseTemplate(template: string, path: string): TranslationCollection { let collection: TranslationCollection = new TranslationCollection(); const regExp: RegExp = /(['"`])((?:(?!\1).|\\\1)+)\1\s*\|\s*translate/g; let matches: RegExpExecArray; while (matches = regExp.exec(template)) { - collection = collection.add(matches[2].split('\\\'').join('\'')); + let keys = [matches[2].split('\\\'').join('\'')]; + let preprocessCtx: KeysPreprocessContextInterface = { + template: template, + path: path + }; + collection = collection.add(this.preprocessKeys(keys, preprocessCtx)[0]); } return collection; diff --git a/src/parsers/service.parser.ts b/src/parsers/service.parser.ts index ae5ca43b..76ef3a13 100644 --- a/src/parsers/service.parser.ts +++ b/src/parsers/service.parser.ts @@ -14,7 +14,9 @@ import { import { ParserInterface } from './parser.interface'; import { AbstractAstParser } from './abstract-ast.parser'; import { TranslationCollection } from '../utils/translation.collection'; +import { injectable } from 'inversify'; +@injectable() export class ServiceParser extends AbstractAstParser implements ParserInterface { protected sourceFile: SourceFile; @@ -39,7 +41,15 @@ export class ServiceParser extends AbstractAstParser implements ParserInterface callNodes.forEach(callNode => { const keys: string[] = this.getStringLiterals(callNode); if (keys && keys.length) { - collection = collection.addKeys(keys); + let preprocessCtx = {template: template, + path: path, + ctxObj: { + sourceFile: this.sourceFile, + classDeclaration: classNode, + propertyName: propertyName, + callExpression: callNode + }}; + collection = collection.addKeys(this.preprocessKeys(keys, preprocessCtx)); } }); }); diff --git a/tests/compilers/namespaced-json.compiler.spec.ts b/tests/compilers/namespaced-json.compiler.spec.ts index df7d68e2..0e247e3f 100644 --- a/tests/compilers/namespaced-json.compiler.spec.ts +++ b/tests/compilers/namespaced-json.compiler.spec.ts @@ -1,3 +1,6 @@ +import 'reflect-metadata'; +import '../../src/ioc/inversify.config'; + import { expect } from 'chai'; import { TranslationCollection } from '../../src/utils/translation.collection'; diff --git a/tests/parsers/directive.parser.spec.ts b/tests/parsers/directive.parser.spec.ts index cc13705a..6f4fb507 100644 --- a/tests/parsers/directive.parser.spec.ts +++ b/tests/parsers/directive.parser.spec.ts @@ -1,3 +1,6 @@ +import 'reflect-metadata'; +import '../../src/ioc/inversify.config'; + import { expect } from 'chai'; import { DirectiveParser } from '../../src/parsers/directive.parser'; diff --git a/tests/parsers/function.parser.spec.ts b/tests/parsers/function.parser.spec.ts index ae32bd11..922dce40 100644 --- a/tests/parsers/function.parser.spec.ts +++ b/tests/parsers/function.parser.spec.ts @@ -1,3 +1,6 @@ +import 'reflect-metadata'; +import '../../src/ioc/inversify.config'; + import { expect } from 'chai'; import { FunctionParser } from '../../src/parsers/function.parser'; diff --git a/tests/parsers/pipe.parser.spec.ts b/tests/parsers/pipe.parser.spec.ts index a6b9faef..0c3a0499 100644 --- a/tests/parsers/pipe.parser.spec.ts +++ b/tests/parsers/pipe.parser.spec.ts @@ -1,3 +1,6 @@ +import 'reflect-metadata'; +import '../../src/ioc/inversify.config'; + import { expect } from 'chai'; import { PipeParser } from '../../src/parsers/pipe.parser'; diff --git a/tests/parsers/service.parser.spec.ts b/tests/parsers/service.parser.spec.ts index 35252dae..81207856 100644 --- a/tests/parsers/service.parser.spec.ts +++ b/tests/parsers/service.parser.spec.ts @@ -1,3 +1,6 @@ +import 'reflect-metadata'; +import '../../src/ioc/inversify.config'; + import { expect } from 'chai'; import { ServiceParser } from '../../src/parsers/service.parser'; diff --git a/tsconfig.json b/tsconfig.json index 6f955341..26acea1f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,11 +5,14 @@ "noImplicitAny": true, "removeComments": true, "declaration": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, "target": "es6", "lib": [ "dom", "es2015" ], + "types": ["reflect-metadata","mocha"], "module": "commonjs", "outDir": "./dist/", "sourceMap": true From 4c8172f841d31d89dd2282a6a32465274ab4fe07 Mon Sep 17 00:00:00 2001 From: Enrico Bottacin Date: Wed, 7 Aug 2019 12:19:00 +0200 Subject: [PATCH 2/9] fix --- bin/cli.js | 11 +++++++- src/ioc/inversify.config.parsers.kml.ts | 27 ------------------- .../namespaced-json.compiler.spec.ts | 5 ++-- 3 files changed, 13 insertions(+), 30 deletions(-) delete mode 100644 src/ioc/inversify.config.parsers.kml.ts diff --git a/bin/cli.js b/bin/cli.js index 6fa9f730..45e23b37 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -1,3 +1,12 @@ #! /usr/bin/env node -require('../dist/cli/cli'); +//need to be imported once per application: @see https://github.com/inversify/InversifyJS/issues/262#issuecomment-227593844 +let reflectMetadata = require('reflect-metadata'); + +//IoC configuration: imported here to allow redefintion for usage as library +let inversifyConfig = require('../dist/ioc/inversify.config'); + +let cli = require('../dist/cli/cli'); + +cli.extractTask.execute(); + diff --git a/src/ioc/inversify.config.parsers.kml.ts b/src/ioc/inversify.config.parsers.kml.ts deleted file mode 100644 index d91beb9d..00000000 --- a/src/ioc/inversify.config.parsers.kml.ts +++ /dev/null @@ -1,27 +0,0 @@ -import TYPES from './types'; -import { Container } from 'inversify'; - -import { KmlServiceParser } from '../custom-parsers/kml.service.parser'; -import { KmlDirectiveParser } from '../custom-parsers/kml.directive.parser'; -import { KmlPipeParser } from '../custom-parsers/kml.pipe.parser'; -import { KmlFunctionParser } from '../custom-parsers/kml.function.parser'; - - -import { setupParsers, IoCParserConfig, IoCCompilerConfig, setupCompilers } from './inversify.config'; -import { KmlCustomCompiler } from '../custom-compilers/kml-custom.compiler'; - -const parsersConfig: IoCParserConfig = { - parsers: [{type: TYPES.ServiceParser, obj: KmlServiceParser}, - {type: TYPES.DirectiveParser, obj: KmlDirectiveParser}, - {type: TYPES.PipeParser, obj: KmlPipeParser} - ], - parsersWithConfig: [{type: TYPES.FunctionParser, obj: KmlFunctionParser}] -}; - -const compilersConfig: IoCCompilerConfig = { - compilers: [KmlCustomCompiler] -}; - -export const configCompilers = (container: Container) => { setupCompilers(container, compilersConfig); }; - -export const configParsers = (container: Container) => { setupParsers(container, parsersConfig); }; diff --git a/tests/compilers/namespaced-json.compiler.spec.ts b/tests/compilers/namespaced-json.compiler.spec.ts index 0e247e3f..db4cd6bd 100644 --- a/tests/compilers/namespaced-json.compiler.spec.ts +++ b/tests/compilers/namespaced-json.compiler.spec.ts @@ -53,9 +53,10 @@ describe('NamespacedJsonCompiler', () => { 'NAMESPACE.KEY.FIRST_KEY': '', 'NAMESPACE.KEY.SECOND_KEY': 'VALUE' }); - const customCompiler = new NamespacedJsonCompiler({ + const customCompiler = new NamespacedJsonCompiler(); + customCompiler.config = { indentation: ' ' - }); + }; const result: string = customCompiler.compile(collection); expect(result).to.equal('{\n "NAMESPACE": {\n "KEY": {\n "FIRST_KEY": "",\n "SECOND_KEY": "VALUE"\n }\n }\n}'); }); From b2ab86478eb4dbb297760aed97199b0e84e9d1da Mon Sep 17 00:00:00 2001 From: Enrico Bottacin Date: Wed, 7 Aug 2019 14:00:35 +0200 Subject: [PATCH 3/9] fix run test --- package-lock.json | 11 ++++++++++- tsconfig.json | 2 +- .../getttext-parser/index.d.ts | 0 3 files changed, 11 insertions(+), 2 deletions(-) rename src/declarations.d.ts => typings/getttext-parser/index.d.ts (100%) diff --git a/package-lock.json b/package-lock.json index 892937ff..3b930c05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@biesbjerg/ngx-translate-extract", - "version": "3.0.0", + "version": "3.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1591,6 +1591,15 @@ "yargs": "^12.0.5" }, "dependencies": { + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", diff --git a/tsconfig.json b/tsconfig.json index 26acea1f..cab7de5a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,12 +7,12 @@ "declaration": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, + "typeRoots" : ["./node_modules/@types", "./typings"], "target": "es6", "lib": [ "dom", "es2015" ], - "types": ["reflect-metadata","mocha"], "module": "commonjs", "outDir": "./dist/", "sourceMap": true diff --git a/src/declarations.d.ts b/typings/getttext-parser/index.d.ts similarity index 100% rename from src/declarations.d.ts rename to typings/getttext-parser/index.d.ts From 1ec6afc6af231ca49cb93ae471180bc8f37ad83d Mon Sep 17 00:00:00 2001 From: Enrico Bottacin Date: Wed, 7 Aug 2019 17:46:34 +0200 Subject: [PATCH 4/9] fix exports and cli.ts --- bin/cli.js | 2 +- src/cli/cli.ts | 235 +++++++++++++++--------------- src/compilers/compiler.factory.ts | 6 +- src/index.ts | 2 + src/ioc/inversify.config.ts | 38 ++--- src/ioc/types.ts | 18 +-- 6 files changed, 154 insertions(+), 147 deletions(-) diff --git a/bin/cli.js b/bin/cli.js index 45e23b37..579b2003 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -8,5 +8,5 @@ let inversifyConfig = require('../dist/ioc/inversify.config'); let cli = require('../dist/cli/cli'); -cli.extractTask.execute(); +cli.getExtractTask().execute(); diff --git a/src/cli/cli.ts b/src/cli/cli.ts index c6077575..2d7f3fe4 100755 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -13,129 +13,134 @@ import { CompilerFactory } from '../compilers/compiler.factory'; import { donateMessage } from '../utils/donate'; import { interfaces } from 'inversify'; -import TYPES from '../ioc/types'; -import container from '../ioc/inversify.config'; +import { TYPES } from '../ioc/types'; +import { container } from '../ioc/inversify.config'; -export const cli = yargs - .usage('Extract strings from files for translation.\nUsage: $0 [options]') - .version(require(__dirname + '/../../package.json').version) - .alias('version', 'v') - .help('help') - .alias('help', 'h') - .option('input', { - alias: 'i', - describe: 'Paths you would like to extract strings from. You can use path expansion, glob patterns and multiple paths', - default: process.env.PWD, - type: 'array', - normalize: true - }) - .check(options => { - options.input.forEach((dir: string) => { - if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) { - throw new Error(`The path you supplied was not found: '${dir}'`); - } +export const getExtractTask = () => { - }); - return true; - }) - .option('patterns', { - alias: 'p', - describe: 'Extract strings from the following file patterns', - type: 'array', - default: ['/**/*.html', '/**/*.ts'] - }) - .option('output', { - alias: 'o', - describe: 'Paths where you would like to save extracted strings. You can use path expansion, glob patterns and multiple paths', - type: 'array', - normalize: true, - required: true - }) - .option('marker', { - alias: 'm', - describe: 'Extract strings passed to a marker function', - default: false, - type: 'string' - }) - .option('format', { - alias: 'f', - describe: 'Output format', - default: 'json', - type: 'string', - choices: ['json', 'namespaced-json', 'pot', 'custom'] - }) - .option('format-indentation', { - alias: 'fi', - describe: 'Output format indentation', - default: '\t', - type: 'string' - }) - .option('replace', { - alias: 'r', - describe: 'Replace the contents of output file if it exists (Merges by default)', - default: false, - type: 'boolean' - }) - .option('sort', { - alias: 's', - describe: 'Sort strings in alphabetical order when saving', - default: false, - type: 'boolean' - }) - .option('clean', { - alias: 'c', - describe: 'Remove obsolete strings when merging', - default: false, - type: 'boolean' - }) - .option('key-as-default-value', { - alias: 'k', - describe: 'Use key as default value for translations', - default: false, - type: 'boolean' - }) - .exitProcess(true) - .parse(process.argv); + const cli = yargs + .usage('Extract strings from files for translation.\nUsage: $0 [options]') + .version(require(__dirname + '/../../package.json').version) + .alias('version', 'v') + .help('help') + .alias('help', 'h') + .option('input', { + alias: 'i', + describe: 'Paths you would like to extract strings from. You can use path expansion, glob patterns and multiple paths', + default: process.env.PWD, + type: 'array', + normalize: true + }) + .check(options => { + options.input.forEach((dir: string) => { + if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) { + throw new Error(`The path you supplied was not found: '${dir}'`); + } + + }); + return true; + }) + .option('patterns', { + alias: 'p', + describe: 'Extract strings from the following file patterns', + type: 'array', + default: ['/**/*.html', '/**/*.ts'] + }) + .option('output', { + alias: 'o', + describe: 'Paths where you would like to save extracted strings. You can use path expansion, glob patterns and multiple paths', + type: 'array', + normalize: true, + required: true + }) + .option('marker', { + alias: 'm', + describe: 'Extract strings passed to a marker function', + default: false, + type: 'string' + }) + .option('format', { + alias: 'f', + describe: 'Output format', + default: 'json', + type: 'string', + choices: ['json', 'namespaced-json', 'pot', 'custom'] + }) + .option('format-indentation', { + alias: 'fi', + describe: 'Output format indentation', + default: '\t', + type: 'string' + }) + .option('replace', { + alias: 'r', + describe: 'Replace the contents of output file if it exists (Merges by default)', + default: false, + type: 'boolean' + }) + .option('sort', { + alias: 's', + describe: 'Sort strings in alphabetical order when saving', + default: false, + type: 'boolean' + }) + .option('clean', { + alias: 'c', + describe: 'Remove obsolete strings when merging', + default: false, + type: 'boolean' + }) + .option('key-as-default-value', { + alias: 'k', + describe: 'Use key as default value for translations', + default: false, + type: 'boolean' + }) + .exitProcess(true) + .parse(process.argv); -export const extractTask = new ExtractTask(cli.input, cli.output, { - replace: cli.replace, - patterns: cli.patterns -}); + const extractTask = new ExtractTask(cli.input, cli.output, { + replace: cli.replace, + patterns: cli.patterns + }); + // Parsers + const parsers: ParserInterface[] = [container.get(TYPES.SERVICE_PARSER), + container.get(TYPES.DIRECTIVE_PARSER), + container.get(TYPES.PIPE_PARSER)]; -// Parsers -const parsers: ParserInterface[] = [container.get(TYPES.ServiceParser), - container.get(TYPES.DirectiveParser), - container.get(TYPES.PipeParser)]; + if (cli.marker) { + let functionParserFactory = container.get>(TYPES.PARSER_WITH_CONFIG_FACTORY); + let functionParser = functionParserFactory({ + identifier: cli.marker + }); + parsers.push( functionParser); + } + extractTask.setParsers(parsers); + + // Post processors + const postProcessors: PostProcessorInterface[] = []; + if (cli.clean) { + postProcessors.push(new PurgeObsoleteKeysPostProcessor()); + } + if (cli.keyAsDefaultValue) { + postProcessors.push(new KeyAsDefaultValuePostProcessor()); + } + if (cli.sort) { + postProcessors.push(new SortByKeyPostProcessor()); + } + extractTask.setPostProcessors(postProcessors); -if (cli.marker) { - let functionParserFactory = container.get>(TYPES.ParserWithConfigFactory); - let functionParser = functionParserFactory({ - identifier: cli.marker + // Compiler + const compiler: CompilerInterface = CompilerFactory.create(cli.format, { + indentation: cli.formatIndentation }); - parsers.push( functionParser); -} -extractTask.setParsers(parsers); + extractTask.setCompiler(compiler); -// Post processors -const postProcessors: PostProcessorInterface[] = []; -if (cli.clean) { - postProcessors.push(new PurgeObsoleteKeysPostProcessor()); -} -if (cli.keyAsDefaultValue) { - postProcessors.push(new KeyAsDefaultValuePostProcessor()); -} -if (cli.sort) { - postProcessors.push(new SortByKeyPostProcessor()); -} -extractTask.setPostProcessors(postProcessors); + //extractTask.execute(); -// Compiler -const compiler: CompilerInterface = CompilerFactory.create(cli.format, { - indentation: cli.formatIndentation -}); -extractTask.setCompiler(compiler); + console.log(donateMessage); -//extractTask.execute(); + return extractTask; +}; -console.log(donateMessage); diff --git a/src/compilers/compiler.factory.ts b/src/compilers/compiler.factory.ts index 00fd0079..288d16f9 100644 --- a/src/compilers/compiler.factory.ts +++ b/src/compilers/compiler.factory.ts @@ -1,12 +1,12 @@ import { CompilerInterface } from '../compilers/compiler.interface'; -import container from '../ioc/inversify.config'; -import TYPES from '../ioc/types'; +import { container } from '../ioc/inversify.config'; +import { TYPES } from '../ioc/types'; import { interfaces } from 'inversify'; export class CompilerFactory { public static create(format: string, options?: any): CompilerInterface { - let compilerFactory = container.get>(TYPES.CompilerFactory); + let compilerFactory = container.get>(TYPES.COMPILER_FACTORY); let compiler = compilerFactory(format, options); return compiler as CompilerInterface; } diff --git a/src/index.ts b/src/index.ts index 032edb4c..0d0f0b0c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ export * from './utils/translation.collection'; export * from './utils/utils'; export * from './ioc/types'; +export * from './ioc/inversify.config'; export * from './cli/cli'; export * from './cli/tasks/task.interface'; @@ -14,6 +15,7 @@ export * from './parsers/pipe.parser'; export * from './parsers/service.parser'; export * from './parsers/function.parser'; +export * from './compilers/abstract-compiler'; export * from './compilers/compiler.interface'; export * from './compilers/compiler.factory'; export * from './compilers/json.compiler'; diff --git a/src/ioc/inversify.config.ts b/src/ioc/inversify.config.ts index ce5a1c61..35049189 100644 --- a/src/ioc/inversify.config.ts +++ b/src/ioc/inversify.config.ts @@ -1,5 +1,5 @@ import { Container, interfaces } from 'inversify'; -import TYPES from './types'; +import { TYPES } from './types'; import { ParserInterface, ParserInterfaceWithConfig } from '../parsers/parser.interface'; import { ServiceParser } from '../parsers/service.parser'; import { DirectiveParser } from '../parsers/directive.parser'; @@ -12,7 +12,7 @@ import { NamespacedJsonCompiler } from '../compilers/namespaced-json.compiler'; import { CustomCompiler } from '../compilers/custom.compiler'; -const container = new Container(); +const _container = new Container(); export interface IoCParserConfig { parsers: {type: symbol, obj: interfaces.Newable}[]; @@ -39,16 +39,16 @@ export const setupParsers = (container: Container, parserConfig: IoCParserConfig }; export const configFactories = (container: Container) => { - container.bind>(TYPES.ParserWithConfigFactory).toFactory( (context: interfaces.Context) => { + container.bind>(TYPES.PARSER_WITH_CONFIG_FACTORY).toFactory( (context: interfaces.Context) => { return (config: any) => { - let parserInterfaceWithConfig = context.container.get(TYPES.FunctionParser); + let parserInterfaceWithConfig = context.container.get(TYPES.FUNCTION_PARSER); parserInterfaceWithConfig.config = config; return parserInterfaceWithConfig; }; }); - container.bind>(TYPES.CompilerFactory).toFactory( (context: interfaces.Context) => { + container.bind>(TYPES.COMPILER_FACTORY).toFactory( (context: interfaces.Context) => { return (format: string, config: any) => { - let compiler = context.container.getNamed(TYPES.Compiler, format); + let compiler = context.container.getNamed(TYPES.COMPILER, format); compiler.config = config; return compiler; }; @@ -59,21 +59,21 @@ export const setupCompilers = (container: Container, compilersConfig?: IoCCompil // container.unbind for named is not implemented yet // as workaround unbind all classes and rebind compilerConfig first then add default compilers if not // already binded - if (container.isBound(TYPES.Compiler)) { - container.unbind(TYPES.Compiler); + if (container.isBound(TYPES.COMPILER)) { + container.unbind(TYPES.COMPILER); } if (compilersConfig !== undefined) { compilersConfig.compilers.forEach( (compiler) => { let selector: string = new compiler().selector; - container.bind(TYPES.Compiler).to(compiler).whenTargetNamed(selector); + container.bind(TYPES.COMPILER).to(compiler).whenTargetNamed(selector); }); } defaultCompilersConfig.compilers.forEach( (compiler) => { let selector: string = new compiler().selector; - if (!container.isBoundNamed(TYPES.Compiler,selector)) { - container.bind(TYPES.Compiler).to(compiler).whenTargetNamed(selector); + if (!container.isBoundNamed(TYPES.COMPILER,selector)) { + container.bind(TYPES.COMPILER).to(compiler).whenTargetNamed(selector); } }); }; @@ -83,15 +83,15 @@ const defaultCompilersConfig: IoCCompilerConfig = { }; const parsersConfig: IoCParserConfig = { - parsers: [{type: TYPES.ServiceParser, obj: ServiceParser}, - {type: TYPES.DirectiveParser, obj: DirectiveParser}, - {type: TYPES.PipeParser, obj: PipeParser} + parsers: [{type: TYPES.SERVICE_PARSER, obj: ServiceParser}, + {type: TYPES.DIRECTIVE_PARSER, obj: DirectiveParser}, + {type: TYPES.PIPE_PARSER, obj: PipeParser} ], - parsersWithConfig: [{type: TYPES.FunctionParser, obj: FunctionParser}] + parsersWithConfig: [{type: TYPES.FUNCTION_PARSER, obj: FunctionParser}] }; -setupParsers(container, parsersConfig); -setupCompilers(container); -configFactories(container); +setupParsers(_container, parsersConfig); +setupCompilers(_container); +configFactories(_container); -export default container; +export const container = _container; diff --git a/src/ioc/types.ts b/src/ioc/types.ts index b9c07efc..584f3c1b 100644 --- a/src/ioc/types.ts +++ b/src/ioc/types.ts @@ -1,11 +1,11 @@ -let TYPES = { - DirectiveParser: Symbol('ParserInterface'), - ServiceParser: Symbol('ParserInterface'), - PipeParser: Symbol('ParserInterface'), - FunctionParser: Symbol('ParserInterface'), - Compiler: Symbol('CompilerInterface'), - ParserWithConfigFactory: Symbol('Factory'), - CompilerFactory: Symbol('Factory') +const types = { + DIRECTIVE_PARSER: Symbol('ParserInterface'), + SERVICE_PARSER: Symbol('ParserInterface'), + PIPE_PARSER: Symbol('ParserInterface'), + FUNCTION_PARSER: Symbol('ParserInterface'), + COMPILER: Symbol('CompilerInterface'), + PARSER_WITH_CONFIG_FACTORY: Symbol('Factory'), + COMPILER_FACTORY: Symbol('Factory') }; -export default TYPES; +export const TYPES = types; From 3c8b6df7ffb4831f5d5338e281e2eca0d06be22d Mon Sep 17 00:00:00 2001 From: Enrico Bottacin Date: Wed, 7 Aug 2019 18:17:23 +0200 Subject: [PATCH 5/9] fix cli --- bin/cli.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/cli.js b/bin/cli.js index 579b2003..cd7f4cc3 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -6,7 +6,8 @@ let reflectMetadata = require('reflect-metadata'); //IoC configuration: imported here to allow redefintion for usage as library let inversifyConfig = require('../dist/ioc/inversify.config'); + let cli = require('../dist/cli/cli'); -cli.getExtractTask().execute(); +cli.extractTask.execute(); From a764056b36059bc2de4f8d6cdda8f179b93f2c1c Mon Sep 17 00:00:00 2001 From: Enrico Bottacin Date: Fri, 9 Aug 2019 17:06:30 +0200 Subject: [PATCH 6/9] added IoC to TaskInterface --- bin/cli.js | 2 +- src/cli/cli.ts | 6 ++++-- src/cli/tasks/extract.task.ts | 21 +++++++++++---------- src/cli/tasks/task.interface.ts | 18 ++++++++++++++++++ src/ioc/inversify.config.ts | 20 +++++++++++++++++++- src/ioc/types.ts | 4 +++- 6 files changed, 56 insertions(+), 15 deletions(-) diff --git a/bin/cli.js b/bin/cli.js index cd7f4cc3..29af3f36 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -9,5 +9,5 @@ let inversifyConfig = require('../dist/ioc/inversify.config'); let cli = require('../dist/cli/cli'); -cli.extractTask.execute(); +cli.getExtractTask().execute(); diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 2d7f3fe4..800c4a59 100755 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -1,7 +1,6 @@ import * as fs from 'fs'; import * as yargs from 'yargs'; -import { ExtractTask } from './tasks/extract.task'; import { ParserInterface, ParserInterfaceWithConfig } from '../parsers/parser.interface'; import { PostProcessorInterface } from '../post-processors/post-processor.interface'; @@ -15,6 +14,7 @@ import { donateMessage } from '../utils/donate'; import { interfaces } from 'inversify'; import { TYPES } from '../ioc/types'; import { container } from '../ioc/inversify.config'; +import { TaskInterface } from './tasks/task.interface'; export const getExtractTask = () => { @@ -99,10 +99,12 @@ export const getExtractTask = () => { .exitProcess(true) .parse(process.argv); - const extractTask = new ExtractTask(cli.input, cli.output, { + const extractTaskFactory = container.get>(TYPES.TASK_FACTORY); + const extractTask = extractTaskFactory(cli.input, cli.output, { replace: cli.replace, patterns: cli.patterns }); + // Parsers const parsers: ParserInterface[] = [container.get(TYPES.SERVICE_PARSER), container.get(TYPES.DIRECTIVE_PARSER), diff --git a/src/cli/tasks/extract.task.ts b/src/cli/tasks/extract.task.ts index b120a525..79e43d07 100644 --- a/src/cli/tasks/extract.task.ts +++ b/src/cli/tasks/extract.task.ts @@ -1,5 +1,5 @@ import { TranslationCollection } from '../../utils/translation.collection'; -import { TaskInterface } from './task.interface'; +import { TaskInterface, ExtractTaskOptionsInterface } from './task.interface'; import { ParserInterface } from '../../parsers/parser.interface'; import { PostProcessorInterface } from '../../post-processors/post-processor.interface'; import { CompilerInterface } from '../../compilers/compiler.interface'; @@ -9,12 +9,9 @@ import * as glob from 'glob'; import * as fs from 'fs'; import * as path from 'path'; import * as mkdirp from 'mkdirp'; +import { injectable } from 'inversify'; -export interface ExtractTaskOptionsInterface { - replace?: boolean; - patterns?: string[]; -} - +@injectable() export class ExtractTask implements TaskInterface { protected options: ExtractTaskOptionsInterface = { @@ -22,14 +19,18 @@ export class ExtractTask implements TaskInterface { patterns: [] }; + protected inputs: string[]; + protected outputs: string[]; + protected parsers: ParserInterface[] = []; protected postProcessors: PostProcessorInterface[] = []; protected compiler: CompilerInterface; - public constructor(protected inputs: string[], protected outputs: string[], options?: ExtractTaskOptionsInterface) { - this.inputs = inputs.map(input => path.resolve(input)); - this.outputs = outputs.map(output => path.resolve(output)); - this.options = { ...this.options, ...options }; + + public setup(input: string[], output: string[], opts?: ExtractTaskOptionsInterface) { + this.inputs = input.map( i => path.resolve(i)); + this.outputs = output.map( o => path.resolve(o)); + this.options = { ...this.options, ...opts }; } public execute(): void { diff --git a/src/cli/tasks/task.interface.ts b/src/cli/tasks/task.interface.ts index 42c079f4..8dd9b9ed 100644 --- a/src/cli/tasks/task.interface.ts +++ b/src/cli/tasks/task.interface.ts @@ -1,3 +1,21 @@ +import { ParserInterface } from '../../parsers/parser.interface'; +import { CompilerInterface } from '../../compilers/compiler.interface'; +import { PostProcessorInterface } from '../../post-processors/post-processor.interface'; + +export interface ExtractTaskOptionsInterface { + replace?: boolean; + patterns?: string[]; +} + export interface TaskInterface { + + setup(input: string[], output: string[], opts?: ExtractTaskOptionsInterface): void; + + setParsers(parsers: ParserInterface[]): void; + + setCompiler(compiler: CompilerInterface): void; + + setPostProcessors(postProcessors: PostProcessorInterface[]): void; + execute(): void; } diff --git a/src/ioc/inversify.config.ts b/src/ioc/inversify.config.ts index 35049189..064e5bb4 100644 --- a/src/ioc/inversify.config.ts +++ b/src/ioc/inversify.config.ts @@ -10,6 +10,8 @@ import { JsonCompiler } from '../compilers/json.compiler'; import { PoCompiler } from '../compilers/po.compiler'; import { NamespacedJsonCompiler } from '../compilers/namespaced-json.compiler'; import { CustomCompiler } from '../compilers/custom.compiler'; +import { TaskInterface, ExtractTaskOptionsInterface } from '../cli/tasks/task.interface'; +import { ExtractTask } from '../cli/tasks/extract.task'; const _container = new Container(); @@ -53,6 +55,13 @@ export const configFactories = (container: Container) => { return compiler; }; }); + container.bind>(TYPES.TASK_FACTORY).toFactory( (context: interfaces.Context) => { + return (input: string[], output: string[], opts?: ExtractTaskOptionsInterface) => { + let task = context.container.get(TYPES.TASK); + task.setup(input, output, opts); + return task; + }; + }); }; export const setupCompilers = (container: Container, compilersConfig?: IoCCompilerConfig) => { @@ -72,12 +81,20 @@ export const setupCompilers = (container: Container, compilersConfig?: IoCCompil defaultCompilersConfig.compilers.forEach( (compiler) => { let selector: string = new compiler().selector; - if (!container.isBoundNamed(TYPES.COMPILER,selector)) { + if (!container.isBoundNamed(TYPES.COMPILER, selector)) { container.bind(TYPES.COMPILER).to(compiler).whenTargetNamed(selector); } }); }; +export const setupTask = (container: Container, extractTask: interfaces.Newable) => { + if (container.isBound(TYPES.TASK)) { + container.unbind(TYPES.TASK); + } + container.bind(TYPES.TASK).to(extractTask); +}; + + const defaultCompilersConfig: IoCCompilerConfig = { compilers: [JsonCompiler, NamespacedJsonCompiler, PoCompiler, CustomCompiler] }; @@ -92,6 +109,7 @@ const parsersConfig: IoCParserConfig = { setupParsers(_container, parsersConfig); setupCompilers(_container); +setupTask(_container, ExtractTask); configFactories(_container); export const container = _container; diff --git a/src/ioc/types.ts b/src/ioc/types.ts index 584f3c1b..390bb680 100644 --- a/src/ioc/types.ts +++ b/src/ioc/types.ts @@ -4,8 +4,10 @@ const types = { PIPE_PARSER: Symbol('ParserInterface'), FUNCTION_PARSER: Symbol('ParserInterface'), COMPILER: Symbol('CompilerInterface'), + TASK: Symbol('TaskInterface'), PARSER_WITH_CONFIG_FACTORY: Symbol('Factory'), - COMPILER_FACTORY: Symbol('Factory') + COMPILER_FACTORY: Symbol('Factory'), + TASK_FACTORY: Symbol('Factory') }; export const TYPES = types; From 3a880e8e08bd872c7ad8f223dc71538cb2c69cdf Mon Sep 17 00:00:00 2001 From: Enrico Bottacin Date: Tue, 20 Aug 2019 09:18:40 +0200 Subject: [PATCH 7/9] removed custom compiler, read possibile compilers from container --- src/cli/cli.ts | 4 +++- src/compilers/custom.compiler.ts | 24 ------------------------ src/ioc/inversify.config.ts | 3 +-- 3 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 src/compilers/custom.compiler.ts diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 800c4a59..b47f7ff8 100755 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -18,6 +18,8 @@ import { TaskInterface } from './tasks/task.interface'; export const getExtractTask = () => { + let selectors = container.getAll(TYPES.COMPILER).map( compiler => compiler.selector); + const cli = yargs .usage('Extract strings from files for translation.\nUsage: $0 [options]') .version(require(__dirname + '/../../package.json').version) @@ -64,7 +66,7 @@ export const getExtractTask = () => { describe: 'Output format', default: 'json', type: 'string', - choices: ['json', 'namespaced-json', 'pot', 'custom'] + choices: selectors }) .option('format-indentation', { alias: 'fi', diff --git a/src/compilers/custom.compiler.ts b/src/compilers/custom.compiler.ts deleted file mode 100644 index 26caeefb..00000000 --- a/src/compilers/custom.compiler.ts +++ /dev/null @@ -1,24 +0,0 @@ - -import { TranslationCollection } from '../utils/translation.collection'; -import { injectable } from 'inversify'; -import { CompilerInterface } from './compiler.interface'; -import { AbstractCompiler } from './abstract-compiler'; - -@injectable() -export class CustomCompiler extends AbstractCompiler implements CompilerInterface { - - public extension: string = 'xml'; - public selector: string = 'custom'; - constructor () { - super(); - } - - public compile(collection: TranslationCollection): string { - throw new Error('not implemented'); - } - - public parse(contents: string): TranslationCollection { - throw new Error('not implemented'); - } - -} diff --git a/src/ioc/inversify.config.ts b/src/ioc/inversify.config.ts index 064e5bb4..5c8fc87b 100644 --- a/src/ioc/inversify.config.ts +++ b/src/ioc/inversify.config.ts @@ -9,7 +9,6 @@ import { CompilerInterface } from '../compilers/compiler.interface'; import { JsonCompiler } from '../compilers/json.compiler'; import { PoCompiler } from '../compilers/po.compiler'; import { NamespacedJsonCompiler } from '../compilers/namespaced-json.compiler'; -import { CustomCompiler } from '../compilers/custom.compiler'; import { TaskInterface, ExtractTaskOptionsInterface } from '../cli/tasks/task.interface'; import { ExtractTask } from '../cli/tasks/extract.task'; @@ -96,7 +95,7 @@ export const setupTask = (container: Container, extractTask: interfaces.Newable< const defaultCompilersConfig: IoCCompilerConfig = { - compilers: [JsonCompiler, NamespacedJsonCompiler, PoCompiler, CustomCompiler] + compilers: [JsonCompiler, NamespacedJsonCompiler, PoCompiler] }; const parsersConfig: IoCParserConfig = { From 1303895e6b4e32397ebb9540774d44ab1d353475 Mon Sep 17 00:00:00 2001 From: Enrico Bottacin Date: Tue, 20 Aug 2019 11:56:51 +0200 Subject: [PATCH 8/9] create factory for TaskInterface --- src/cli/cli.ts | 48 +++++++++-------------------------- src/cli/tasks/task.factory.ts | 47 ++++++++++++++++++++++++++++++++++ src/index.ts | 1 + 3 files changed, 60 insertions(+), 36 deletions(-) create mode 100644 src/cli/tasks/task.factory.ts diff --git a/src/cli/cli.ts b/src/cli/cli.ts index b47f7ff8..a56a14b0 100755 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -1,20 +1,17 @@ import * as fs from 'fs'; import * as yargs from 'yargs'; -import { ParserInterface, ParserInterfaceWithConfig } from '../parsers/parser.interface'; import { PostProcessorInterface } from '../post-processors/post-processor.interface'; import { SortByKeyPostProcessor } from '../post-processors/sort-by-key.post-processor'; import { KeyAsDefaultValuePostProcessor } from '../post-processors/key-as-default-value.post-processor'; import { PurgeObsoleteKeysPostProcessor } from '../post-processors/purge-obsolete-keys.post-processor'; import { CompilerInterface } from '../compilers/compiler.interface'; -import { CompilerFactory } from '../compilers/compiler.factory'; import { donateMessage } from '../utils/donate'; -import { interfaces } from 'inversify'; import { TYPES } from '../ioc/types'; import { container } from '../ioc/inversify.config'; -import { TaskInterface } from './tasks/task.interface'; +import { TaskFactoryOptions, createTask } from './tasks/task.factory'; export const getExtractTask = () => { @@ -101,26 +98,7 @@ export const getExtractTask = () => { .exitProcess(true) .parse(process.argv); - const extractTaskFactory = container.get>(TYPES.TASK_FACTORY); - const extractTask = extractTaskFactory(cli.input, cli.output, { - replace: cli.replace, - patterns: cli.patterns - }); - - // Parsers - const parsers: ParserInterface[] = [container.get(TYPES.SERVICE_PARSER), - container.get(TYPES.DIRECTIVE_PARSER), - container.get(TYPES.PIPE_PARSER)]; - - - if (cli.marker) { - let functionParserFactory = container.get>(TYPES.PARSER_WITH_CONFIG_FACTORY); - let functionParser = functionParserFactory({ - identifier: cli.marker - }); - parsers.push( functionParser); - } - extractTask.setParsers(parsers); + console.log(donateMessage); // Post processors const postProcessors: PostProcessorInterface[] = []; @@ -133,18 +111,16 @@ export const getExtractTask = () => { if (cli.sort) { postProcessors.push(new SortByKeyPostProcessor()); } - extractTask.setPostProcessors(postProcessors); - // Compiler - const compiler: CompilerInterface = CompilerFactory.create(cli.format, { - indentation: cli.formatIndentation - }); - extractTask.setCompiler(compiler); - - //extractTask.execute(); - - console.log(donateMessage); - - return extractTask; + const taskFactoryOptions: TaskFactoryOptions = { + replace: cli.replace, + patterns: cli.patterns, + format: cli.format, + formatIndentation: cli['format-indentation'], + marker: cli.marker, + postProcessors: postProcessors + }; + + return createTask(cli.input, cli.output, taskFactoryOptions); }; diff --git a/src/cli/tasks/task.factory.ts b/src/cli/tasks/task.factory.ts new file mode 100644 index 00000000..865bb6d5 --- /dev/null +++ b/src/cli/tasks/task.factory.ts @@ -0,0 +1,47 @@ + +import { interfaces } from 'inversify'; +import { PostProcessorInterface } from '../../post-processors/post-processor.interface'; +import { TaskInterface, ExtractTaskOptionsInterface } from './task.interface'; +import { TYPES } from '../../ioc/types'; +import { container } from '../../ioc/inversify.config'; +import { ParserInterface, ParserInterfaceWithConfig } from '../../parsers/parser.interface'; +import { CompilerInterface } from '../../compilers/compiler.interface'; +import { CompilerFactory } from '../../compilers/compiler.factory'; + +export abstract class TaskFactoryOptions { + public replace: boolean = false; + public patterns: string[] = ['/**/*.html', '/**/*.ts']; + public format: string; + public marker?: boolean; + public postProcessors?: PostProcessorInterface[]; + public formatIndentation?: string = '\t'; +} + +export function createTask (input: string, output: string[], options: TaskFactoryOptions): TaskInterface { + const extractTaskFactory = container.get>(TYPES.TASK_FACTORY); + const opts: ExtractTaskOptionsInterface = (({ replace, patterns }) => ({ replace, patterns }))(options); + const extractTask = extractTaskFactory(input, output, opts); + + const parsers: ParserInterface[] = [container.get(TYPES.SERVICE_PARSER), + container.get(TYPES.DIRECTIVE_PARSER), + container.get(TYPES.PIPE_PARSER)]; + + if (options.marker !== undefined ) { + + let functionParserFactory = container.get>(TYPES.PARSER_WITH_CONFIG_FACTORY); + let functionParser = functionParserFactory({ + identifier: options.marker + }); + parsers.push( functionParser); + } + extractTask.setParsers(parsers); + extractTask.setPostProcessors(options.postProcessors); + + // Compiler + const compiler: CompilerInterface = CompilerFactory.create(options.format, { + indentation: options.formatIndentation + }); + extractTask.setCompiler(compiler); + + return extractTask; +} diff --git a/src/index.ts b/src/index.ts index 0d0f0b0c..e2581835 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,7 @@ export * from './ioc/inversify.config'; export * from './cli/cli'; export * from './cli/tasks/task.interface'; export * from './cli/tasks/extract.task'; +export * from './cli/tasks/task.factory'; export * from './parsers/parser.interface'; export * from './parsers/abstract-ast.parser'; From dab05127660cead00d374b7fc128d3d7741074e9 Mon Sep 17 00:00:00 2001 From: Enrico Bottacin Date: Tue, 20 Aug 2019 11:56:51 +0200 Subject: [PATCH 9/9] fix taskFactory Signature and make TaskFactoryOptions not abstract --- src/cli/tasks/task.factory.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/cli/tasks/task.factory.ts b/src/cli/tasks/task.factory.ts index 865bb6d5..8ecd9074 100644 --- a/src/cli/tasks/task.factory.ts +++ b/src/cli/tasks/task.factory.ts @@ -1,4 +1,3 @@ - import { interfaces } from 'inversify'; import { PostProcessorInterface } from '../../post-processors/post-processor.interface'; import { TaskInterface, ExtractTaskOptionsInterface } from './task.interface'; @@ -8,18 +7,18 @@ import { ParserInterface, ParserInterfaceWithConfig } from '../../parsers/parser import { CompilerInterface } from '../../compilers/compiler.interface'; import { CompilerFactory } from '../../compilers/compiler.factory'; -export abstract class TaskFactoryOptions { +export class TaskFactoryOptions { public replace: boolean = false; public patterns: string[] = ['/**/*.html', '/**/*.ts']; + public postProcessors: PostProcessorInterface[] = []; public format: string; - public marker?: boolean; - public postProcessors?: PostProcessorInterface[]; - public formatIndentation?: string = '\t'; + public marker: boolean = false; + public formatIndentation: string = '\t'; } -export function createTask (input: string, output: string[], options: TaskFactoryOptions): TaskInterface { +export function createTask (input: string[], output: string[], options: TaskFactoryOptions): TaskInterface { const extractTaskFactory = container.get>(TYPES.TASK_FACTORY); - const opts: ExtractTaskOptionsInterface = (({ replace, patterns }) => ({ replace, patterns }))(options); + const opts: ExtractTaskOptionsInterface = (({ replace, patterns }) => ({ replace, patterns }))(options); const extractTask = extractTaskFactory(input, output, opts); const parsers: ParserInterface[] = [container.get(TYPES.SERVICE_PARSER),