Add StringCollection to make it easier to work with strings
This commit is contained in:
@@ -1,17 +1,17 @@
|
||||
import { Extractor } from './extractor';
|
||||
import { JsonSerializer } from './serializers/json.serializer';
|
||||
import { StringCollection } from './utils/string.collection';
|
||||
|
||||
const serializer = new JsonSerializer();
|
||||
// Or const serializer = new PotSerializer();
|
||||
const extractor = new Extractor(serializer);
|
||||
|
||||
const src = '/your/project';
|
||||
const dest = '/your/project/template.json';
|
||||
|
||||
try {
|
||||
const messages: string[] = extractor.extract(src);
|
||||
const collection: StringCollection = extractor.process(src);
|
||||
const output: string = extractor.save(dest);
|
||||
console.log({ messages, output });
|
||||
console.log({ strings: collection.keys(), output: output });
|
||||
} catch (e) {
|
||||
console.log(`Something went wrong: ${e.toString()}`);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ import { PipeParser } from './parsers/pipe.parser';
|
||||
import { DirectiveParser } from './parsers/directive.parser';
|
||||
import { ServiceParser } from './parsers/service.parser';
|
||||
import { SerializerInterface } from './serializers/serializer.interface';
|
||||
import { StringCollection } from './utils/string.collection';
|
||||
|
||||
import * as lodash from 'lodash';
|
||||
import * as glob from 'glob';
|
||||
import * as fs from 'fs';
|
||||
|
||||
@@ -16,35 +16,35 @@ export class Extractor {
|
||||
new ServiceParser()
|
||||
];
|
||||
|
||||
public globPatterns: string[] = [
|
||||
public find: string[] = [
|
||||
'/**/*.html',
|
||||
'/**/*.ts',
|
||||
'/**/*.js'
|
||||
];
|
||||
|
||||
public messages: string[] = [];
|
||||
public collection: StringCollection = new StringCollection();
|
||||
|
||||
public constructor(public serializer: SerializerInterface) { }
|
||||
|
||||
/**
|
||||
* Extracts messages from paths
|
||||
* Process dir
|
||||
*/
|
||||
public extract(dir: string): string[] {
|
||||
let messages = [];
|
||||
|
||||
this._getFiles(dir).forEach(filePath => {
|
||||
const result = this._extractMessages(filePath);
|
||||
messages = [...messages, ...result];
|
||||
public process(dir: string): StringCollection {
|
||||
this._getFiles(dir).forEach(path => {
|
||||
const contents: string = fs.readFileSync(path, 'utf-8');
|
||||
this.parsers.forEach((parser: ParserInterface) => {
|
||||
this.collection.merge(parser.extract(contents, path));
|
||||
});
|
||||
});
|
||||
|
||||
return this.messages = lodash.uniq(messages);
|
||||
return this.collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize and return output
|
||||
*/
|
||||
public serialize(): string {
|
||||
return this.serializer.serialize(this.messages);
|
||||
return this.serializer.serialize(this.collection);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,10 +62,10 @@ export class Extractor {
|
||||
protected _getFiles(dir: string): string[] {
|
||||
let results: string[] = [];
|
||||
|
||||
this.globPatterns.forEach(globPattern => {
|
||||
this.find.forEach(pattern => {
|
||||
const files = glob
|
||||
.sync(dir + globPattern)
|
||||
.filter(filePath => fs.statSync(filePath).isFile());
|
||||
.sync(dir + pattern)
|
||||
.filter(path => fs.statSync(path).isFile());
|
||||
|
||||
results = [...results, ...files];
|
||||
});
|
||||
@@ -73,18 +73,4 @@ export class Extractor {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract messages from file using parser
|
||||
*/
|
||||
protected _extractMessages(filePath: string): string[] {
|
||||
let results: string[] = [];
|
||||
|
||||
const contents: string = fs.readFileSync(filePath, 'utf-8');
|
||||
this.parsers.forEach((parser: ParserInterface) => {
|
||||
results = [...results, ...parser.process(filePath, contents)];
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ export abstract class AbstractTemplateParser {
|
||||
* Checks if file is of type javascript or typescript and
|
||||
* makes the assumption that it is an Angular Component
|
||||
*/
|
||||
protected _isAngularComponent(filePath: string): boolean {
|
||||
return new RegExp(/\.(ts|js)$/, 'i').test(filePath);
|
||||
protected _isAngularComponent(path: string): boolean {
|
||||
return new RegExp(/\.(ts|js)$/, 'i').test(path);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import { ParserInterface } from './parser.interface';
|
||||
import { AbstractTemplateParser } from './abstract-template.parser';
|
||||
import { StringCollection } from '../utils/string.collection';
|
||||
|
||||
import * as $ from 'cheerio';
|
||||
|
||||
export class DirectiveParser extends AbstractTemplateParser implements ParserInterface {
|
||||
|
||||
public process(filePath: string, contents: string): string[] {
|
||||
if (this._isAngularComponent(filePath)) {
|
||||
public extract(contents: string, path?: string): StringCollection {
|
||||
if (path && this._isAngularComponent(path)) {
|
||||
contents = this._extractInlineTemplate(contents);
|
||||
}
|
||||
|
||||
return this._parseTemplate(contents);
|
||||
}
|
||||
|
||||
protected _parseTemplate(template: string): string[] {
|
||||
let results: string[] = [];
|
||||
protected _parseTemplate(template: string): StringCollection {
|
||||
const collection = new StringCollection();
|
||||
|
||||
template = this._normalizeTemplateAttributes(template);
|
||||
$(template)
|
||||
@@ -25,7 +26,7 @@ export class DirectiveParser extends AbstractTemplateParser implements ParserInt
|
||||
const attr = $element.attr('translate') || $element.attr('ng2-translate');
|
||||
|
||||
if (attr) {
|
||||
results.push(attr);
|
||||
collection.add(attr);
|
||||
} else {
|
||||
$element
|
||||
.contents()
|
||||
@@ -33,11 +34,11 @@ export class DirectiveParser extends AbstractTemplateParser implements ParserInt
|
||||
.filter(textNode => textNode.type === 'text')
|
||||
.map(textNode => textNode.nodeValue.trim())
|
||||
.filter(text => text.length > 0)
|
||||
.forEach(text => results.push(text));
|
||||
.forEach(text => collection.add(text));
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
return collection;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { StringCollection } from '../utils/string.collection';
|
||||
|
||||
export interface ParserInterface {
|
||||
|
||||
process(filePath: string, contents: string): string[];
|
||||
extract(contents: string, path?: string): StringCollection;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
import { ParserInterface } from './parser.interface';
|
||||
import { AbstractTemplateParser } from './abstract-template.parser';
|
||||
import { StringCollection } from '../utils/string.collection';
|
||||
|
||||
export class PipeParser extends AbstractTemplateParser implements ParserInterface {
|
||||
|
||||
public process(filePath: string, contents: string): string[] {
|
||||
if (this._isAngularComponent(filePath)) {
|
||||
public extract(contents: string, path?: string): StringCollection {
|
||||
if (path && this._isAngularComponent(path)) {
|
||||
contents = this._extractInlineTemplate(contents);
|
||||
}
|
||||
|
||||
return this._parseTemplate(contents);
|
||||
}
|
||||
|
||||
protected _parseTemplate(template: string): string[] {
|
||||
let results: string[] = [];
|
||||
protected _parseTemplate(template: string): StringCollection {
|
||||
const collection = new StringCollection();
|
||||
|
||||
const regExp = new RegExp(/([\'"`])([^\1\r\n]*)\1\s+\|\s*translate(:.*?)?/, 'g');
|
||||
|
||||
let matches;
|
||||
while (matches = regExp.exec(template)) {
|
||||
results.push(matches[2]);
|
||||
collection.add(matches[2]);
|
||||
}
|
||||
|
||||
return results;
|
||||
return collection;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { ParserInterface } from './parser.interface';
|
||||
import { StringCollection } from '../utils/string.collection';
|
||||
|
||||
export class ServiceParser implements ParserInterface {
|
||||
|
||||
public process(filePath: string, contents: string): string[] {
|
||||
let results: string[] = [];
|
||||
public extract(contents: string, path?: string): StringCollection {
|
||||
const collection = new StringCollection();
|
||||
|
||||
const translateServiceVar = this._extractTranslateServiceVar(contents);
|
||||
if (!translateServiceVar) {
|
||||
return results;
|
||||
return collection;
|
||||
}
|
||||
|
||||
const methodRegExp: RegExp = new RegExp(/(?:get|instant)\s*\(\s*(\[?([\'"`])([^\1\r\n]+)\2\]?)/);
|
||||
@@ -16,13 +17,13 @@ export class ServiceParser implements ParserInterface {
|
||||
let matches;
|
||||
while (matches = regExp.exec(contents)) {
|
||||
if (this._stringContainsArray(matches[1])) {
|
||||
results.push(...this._stringToArray(matches[1]));
|
||||
collection.add(this._stringToArray(matches[1]));
|
||||
} else {
|
||||
results.push(matches[3]);
|
||||
collection.add(matches[3]);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
return collection;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { SerializerInterface } from './serializer.interface';
|
||||
import { StringCollection } from '../utils/string.collection';
|
||||
|
||||
export class JsonSerializer implements SerializerInterface {
|
||||
|
||||
public serialize(messages: string[]): string {
|
||||
let result = {};
|
||||
messages.forEach(message => {
|
||||
result[message] = '';
|
||||
});
|
||||
|
||||
return JSON.stringify(result, null, '\t');
|
||||
public serialize(collection: StringCollection): string {
|
||||
return JSON.stringify(collection.values, null, '\t');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { SerializerInterface } from './serializer.interface';
|
||||
import { StringCollection } from '../utils/string.collection';
|
||||
|
||||
export class PotSerializer implements SerializerInterface {
|
||||
|
||||
@@ -9,10 +10,10 @@ export class PotSerializer implements SerializerInterface {
|
||||
|
||||
protected _buffer: string[] = [];
|
||||
|
||||
public serialize(messages: string[]): string {
|
||||
public serialize(collection: StringCollection): string {
|
||||
this._reset();
|
||||
this._addHeader(this._headers);
|
||||
this._addMessages(messages);
|
||||
this._addMessages(collection);
|
||||
|
||||
return this._buffer.join('\n');
|
||||
}
|
||||
@@ -25,10 +26,10 @@ export class PotSerializer implements SerializerInterface {
|
||||
});
|
||||
}
|
||||
|
||||
protected _addMessages(messages: string[]): void {
|
||||
messages.forEach(message => {
|
||||
this._add('msgid', message);
|
||||
this._add('msgstr', '');
|
||||
protected _addMessages(collection: StringCollection): void {
|
||||
Object.keys(collection.values).forEach(key => {
|
||||
this._add('msgid', key);
|
||||
this._add('msgstr', collection.get(key));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { StringCollection } from '../utils/string.collection';
|
||||
|
||||
export interface SerializerInterface {
|
||||
|
||||
serialize(messages: string[]): string;
|
||||
serialize(collection: StringCollection): string;
|
||||
|
||||
}
|
||||
|
||||
51
src/utils/string.collection.ts
Normal file
51
src/utils/string.collection.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
export interface StringType {
|
||||
[key: string]: string
|
||||
};
|
||||
|
||||
export class StringCollection {
|
||||
|
||||
public values: StringType = {};
|
||||
|
||||
public static fromObject(values: StringType): StringCollection {
|
||||
const collection = new StringCollection();
|
||||
Object.keys(values).forEach(key => collection.add(key, values[key]));
|
||||
return collection;
|
||||
}
|
||||
|
||||
public static fromArray(keys: string[]): StringCollection {
|
||||
const collection = new StringCollection();
|
||||
keys.forEach(key => collection.add(key));
|
||||
return collection;
|
||||
}
|
||||
|
||||
public add(keys: string | string[], val: string = ''): StringCollection {
|
||||
if (!Array.isArray(keys)) {
|
||||
keys = [keys];
|
||||
}
|
||||
keys.forEach(key => this.values[key] = val);
|
||||
return this;
|
||||
}
|
||||
|
||||
public remove(key: string): StringCollection {
|
||||
delete this.values[key];
|
||||
return this;
|
||||
}
|
||||
|
||||
public merge(collection: StringCollection): StringCollection {
|
||||
this.values = Object.assign({}, this.values, collection.values);
|
||||
return this;
|
||||
}
|
||||
|
||||
public get(key: string): string {
|
||||
return this.values[key];
|
||||
}
|
||||
|
||||
public keys(): string[] {
|
||||
return Object.keys(this.values);
|
||||
}
|
||||
|
||||
public count(): number {
|
||||
return Object.keys(this.values).length;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user