@rushstack/localization-utilities 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,6 +24,14 @@ export declare interface ILocalizedString {
24
24
  comment?: string;
25
25
  }
26
26
 
27
+ /**
28
+ * @public
29
+ */
30
+ export declare interface IParseFileOptions {
31
+ content: string;
32
+ filePath: string;
33
+ }
34
+
27
35
  /**
28
36
  * @public
29
37
  */
@@ -31,6 +39,7 @@ export declare interface IParseLocFileOptions {
31
39
  terminal: ITerminal;
32
40
  filePath: string;
33
41
  content: string;
42
+ parser?: ParserKind;
34
43
  resxNewlineNormalization: NewlineKind | undefined;
35
44
  ignoreMissingResxComments: boolean | undefined;
36
45
  }
@@ -74,6 +83,8 @@ export declare interface ITypingsGeneratorOptions {
74
83
  globsToIgnore?: string[];
75
84
  resxNewlineNormalization?: NewlineKind | undefined;
76
85
  ignoreMissingResxComments?: boolean | undefined;
86
+ ignoreString?: (resxFilePath: string, stringName: string) => boolean;
87
+ processComment?: (comment: string | undefined, resxFilePath: string, stringName: string) => string | undefined;
77
88
  }
78
89
 
79
90
  /**
@@ -81,6 +92,21 @@ export declare interface ITypingsGeneratorOptions {
81
92
  */
82
93
  export declare function parseLocFile(options: IParseLocFileOptions): ILocalizationFile;
83
94
 
95
+ /**
96
+ * @public
97
+ */
98
+ export declare function parseLocJson(options: IParseFileOptions): ILocalizationFile;
99
+
100
+ /**
101
+ * @public
102
+ */
103
+ export declare function parseResJson(options: IParseFileOptions): ILocalizationFile;
104
+
105
+ /**
106
+ * @public
107
+ */
108
+ export declare type ParserKind = 'resx' | 'loc.json' | 'resjson';
109
+
84
110
  /**
85
111
  * @public
86
112
  */
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.24.2"
8
+ "packageVersion": "7.25.0"
9
9
  }
10
10
  ]
11
11
  }
@@ -1,5 +1,9 @@
1
1
  import { ITerminal, NewlineKind } from '@rushstack/node-core-library';
2
2
  import { ILocalizationFile } from './interfaces';
3
+ /**
4
+ * @public
5
+ */
6
+ export declare type ParserKind = 'resx' | 'loc.json' | 'resjson';
3
7
  /**
4
8
  * @public
5
9
  */
@@ -7,9 +11,11 @@ export interface IParseLocFileOptions {
7
11
  terminal: ITerminal;
8
12
  filePath: string;
9
13
  content: string;
14
+ parser?: ParserKind;
10
15
  resxNewlineNormalization: NewlineKind | undefined;
11
16
  ignoreMissingResxComments: boolean | undefined;
12
17
  }
18
+ export declare function selectParserByFilePath(filePath: string): ParserKind;
13
19
  /**
14
20
  * @public
15
21
  */
@@ -1 +1 @@
1
- {"version":3,"file":"LocFileParser.d.ts","sourceRoot":"","sources":["../src/LocFileParser.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAwB,MAAM,8BAA8B,CAAC;AAE5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAKjD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB,EAAE,WAAW,GAAG,SAAS,CAAC;IAClD,yBAAyB,EAAE,OAAO,GAAG,SAAS,CAAC;CAChD;AASD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,iBAAiB,CA0D7E"}
1
+ {"version":3,"file":"LocFileParser.d.ts","sourceRoot":"","sources":["../src/LocFileParser.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAKjD;;GAEG;AACH,oBAAY,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,wBAAwB,EAAE,WAAW,GAAG,SAAS,CAAC;IAClD,yBAAyB,EAAE,OAAO,GAAG,SAAS,CAAC;CAChD;AASD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAUnE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,iBAAiB,CA4B7E"}
@@ -2,72 +2,58 @@
2
2
  // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3
3
  // See LICENSE in the project root for license information.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.parseLocFile = void 0;
6
- const node_core_library_1 = require("@rushstack/node-core-library");
5
+ exports.parseLocFile = exports.selectParserByFilePath = void 0;
6
+ const parseLocJson_1 = require("./parsers/parseLocJson");
7
+ const parseResJson_1 = require("./parsers/parseResJson");
7
8
  const ResxReader_1 = require("./ResxReader");
8
- const LOC_JSON_SCHEMA = node_core_library_1.JsonSchema.fromFile(`${__dirname}/schemas/locJson.schema.json`);
9
9
  const parseCache = new Map();
10
+ function selectParserByFilePath(filePath) {
11
+ if (/\.resx$/i.test(filePath)) {
12
+ return 'resx';
13
+ }
14
+ else if (/\.(resx|loc)\.json$/i.test(filePath)) {
15
+ return 'loc.json';
16
+ }
17
+ else if (/\.resjson$/i.test(filePath)) {
18
+ return 'resjson';
19
+ }
20
+ else {
21
+ throw new Error(`Unsupported file extension in file: ${filePath}`);
22
+ }
23
+ }
24
+ exports.selectParserByFilePath = selectParserByFilePath;
10
25
  /**
11
26
  * @public
12
27
  */
13
28
  function parseLocFile(options) {
14
- const fileCacheKey = `${options.filePath}?${options.resxNewlineNormalization || 'none'}`;
15
- if (parseCache.has(fileCacheKey)) {
16
- const entry = parseCache.get(fileCacheKey);
17
- if (entry.content === options.content) {
18
- return entry.parsedFile;
19
- }
20
- }
29
+ const { parser = selectParserByFilePath(options.filePath) } = options;
21
30
  let parsedFile;
22
- if (/\.resx$/i.test(options.filePath)) {
31
+ if (parser === 'resx') {
32
+ const fileCacheKey = `${options.filePath}?${options.resxNewlineNormalization || 'none'}`;
33
+ if (parseCache.has(fileCacheKey)) {
34
+ const entry = parseCache.get(fileCacheKey);
35
+ if (entry.content === options.content) {
36
+ return entry.parsedFile;
37
+ }
38
+ }
23
39
  parsedFile = (0, ResxReader_1.readResxAsLocFile)(options.content, {
24
40
  terminal: options.terminal,
25
41
  resxFilePath: options.filePath,
26
42
  newlineNormalization: options.resxNewlineNormalization,
27
43
  warnOnMissingComment: !options.ignoreMissingResxComments
28
44
  });
45
+ parseCache.set(fileCacheKey, { content: options.content, parsedFile });
46
+ return parsedFile;
29
47
  }
30
- else if (/\.(resx|loc)\.json$/i.test(options.filePath)) {
31
- parsedFile = node_core_library_1.JsonFile.parseString(options.content);
32
- try {
33
- LOC_JSON_SCHEMA.validateObject(parsedFile, options.filePath);
34
- }
35
- catch (e) {
36
- options.terminal.writeError(`The loc file is invalid. Error: ${e}`);
37
- }
48
+ else if (parser === 'loc.json') {
49
+ return (0, parseLocJson_1.parseLocJson)(options);
38
50
  }
39
- else if (/\.resjson$/i.test(options.filePath)) {
40
- const resjsonFile = node_core_library_1.JsonFile.parseString(options.content);
41
- parsedFile = {};
42
- const comments = new Map();
43
- for (const [key, value] of Object.entries(resjsonFile)) {
44
- if (key.startsWith('_') && key.endsWith('.comment')) {
45
- const commentKey = key.substring(1, key.length - '.comment'.length);
46
- comments.set(commentKey, value);
47
- }
48
- else {
49
- parsedFile[key] = { value };
50
- }
51
- }
52
- const orphanComments = [];
53
- for (const [key, comment] of comments) {
54
- if (parsedFile[key]) {
55
- parsedFile[key].comment = comment;
56
- }
57
- else {
58
- orphanComments.push(key);
59
- }
60
- }
61
- if (orphanComments.length > 0) {
62
- options.terminal.writeErrorLine('The resjson file is invalid. Comments exist for the following string keys ' +
63
- `that don't have values: ${orphanComments.join(', ')}.`);
64
- }
51
+ else if (parser === 'resjson') {
52
+ return (0, parseResJson_1.parseResJson)(options);
65
53
  }
66
54
  else {
67
- throw new Error(`Unsupported file extension in file: ${options.filePath}`);
55
+ throw new Error(`Unsupported parser: ${parser}`);
68
56
  }
69
- parseCache.set(fileCacheKey, { content: options.content, parsedFile });
70
- return parsedFile;
71
57
  }
72
58
  exports.parseLocFile = parseLocFile;
73
59
  //# sourceMappingURL=LocFileParser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LocFileParser.js","sourceRoot":"","sources":["../src/LocFileParser.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { ITerminal, NewlineKind, JsonFile, JsonSchema } from '@rushstack/node-core-library';\n\nimport { ILocalizationFile } from './interfaces';\nimport { readResxAsLocFile } from './ResxReader';\n\nconst LOC_JSON_SCHEMA: JsonSchema = JsonSchema.fromFile(`${__dirname}/schemas/locJson.schema.json`);\n\n/**\n * @public\n */\nexport interface IParseLocFileOptions {\n terminal: ITerminal;\n filePath: string;\n content: string;\n resxNewlineNormalization: NewlineKind | undefined;\n ignoreMissingResxComments: boolean | undefined;\n}\n\ninterface IParseCacheEntry {\n content: string;\n parsedFile: ILocalizationFile;\n}\n\nconst parseCache: Map<string, IParseCacheEntry> = new Map<string, IParseCacheEntry>();\n\n/**\n * @public\n */\nexport function parseLocFile(options: IParseLocFileOptions): ILocalizationFile {\n const fileCacheKey: string = `${options.filePath}?${options.resxNewlineNormalization || 'none'}`;\n if (parseCache.has(fileCacheKey)) {\n const entry: IParseCacheEntry = parseCache.get(fileCacheKey)!;\n if (entry.content === options.content) {\n return entry.parsedFile;\n }\n }\n\n let parsedFile: ILocalizationFile;\n if (/\\.resx$/i.test(options.filePath)) {\n parsedFile = readResxAsLocFile(options.content, {\n terminal: options.terminal,\n resxFilePath: options.filePath,\n newlineNormalization: options.resxNewlineNormalization,\n warnOnMissingComment: !options.ignoreMissingResxComments\n });\n } else if (/\\.(resx|loc)\\.json$/i.test(options.filePath)) {\n parsedFile = JsonFile.parseString(options.content);\n try {\n LOC_JSON_SCHEMA.validateObject(parsedFile, options.filePath);\n } catch (e) {\n options.terminal.writeError(`The loc file is invalid. Error: ${e}`);\n }\n } else if (/\\.resjson$/i.test(options.filePath)) {\n const resjsonFile: Record<string, string> = JsonFile.parseString(options.content);\n parsedFile = {};\n const comments: Map<string, string> = new Map();\n for (const [key, value] of Object.entries(resjsonFile)) {\n if (key.startsWith('_') && key.endsWith('.comment')) {\n const commentKey: string = key.substring(1, key.length - '.comment'.length);\n comments.set(commentKey, value);\n } else {\n parsedFile[key] = { value };\n }\n }\n\n const orphanComments: string[] = [];\n for (const [key, comment] of comments) {\n if (parsedFile[key]) {\n parsedFile[key].comment = comment;\n } else {\n orphanComments.push(key);\n }\n }\n\n if (orphanComments.length > 0) {\n options.terminal.writeErrorLine(\n 'The resjson file is invalid. Comments exist for the following string keys ' +\n `that don't have values: ${orphanComments.join(', ')}.`\n );\n }\n } else {\n throw new Error(`Unsupported file extension in file: ${options.filePath}`);\n }\n\n parseCache.set(fileCacheKey, { content: options.content, parsedFile });\n return parsedFile;\n}\n"]}
1
+ {"version":3,"file":"LocFileParser.js","sourceRoot":"","sources":["../src/LocFileParser.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAK3D,yDAAsD;AACtD,yDAAsD;AACtD,6CAAiD;AAwBjD,MAAM,UAAU,GAAkC,IAAI,GAAG,EAA4B,CAAC;AAEtF,SAAgB,sBAAsB,CAAC,QAAgB;IACrD,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;QAC7B,OAAO,MAAM,CAAC;KACf;SAAM,IAAI,sBAAsB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;QAChD,OAAO,UAAU,CAAC;KACnB;SAAM,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;QACvC,OAAO,SAAS,CAAC;KAClB;SAAM;QACL,MAAM,IAAI,KAAK,CAAC,uCAAuC,QAAQ,EAAE,CAAC,CAAC;KACpE;AACH,CAAC;AAVD,wDAUC;AAED;;GAEG;AACH,SAAgB,YAAY,CAAC,OAA6B;IACxD,MAAM,EAAE,MAAM,GAAG,sBAAsB,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,GAAG,OAAO,CAAC;IAEtE,IAAI,UAA6B,CAAC;IAClC,IAAI,MAAM,KAAK,MAAM,EAAE;QACrB,MAAM,YAAY,GAAW,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,wBAAwB,IAAI,MAAM,EAAE,CAAC;QACjG,IAAI,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;YAChC,MAAM,KAAK,GAAqB,UAAU,CAAC,GAAG,CAAC,YAAY,CAAE,CAAC;YAC9D,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE;gBACrC,OAAO,KAAK,CAAC,UAAU,CAAC;aACzB;SACF;QACD,UAAU,GAAG,IAAA,8BAAiB,EAAC,OAAO,CAAC,OAAO,EAAE;YAC9C,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,YAAY,EAAE,OAAO,CAAC,QAAQ;YAC9B,oBAAoB,EAAE,OAAO,CAAC,wBAAwB;YACtD,oBAAoB,EAAE,CAAC,OAAO,CAAC,yBAAyB;SACzD,CAAC,CAAC;QACH,UAAU,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;QAEvE,OAAO,UAAU,CAAC;KACnB;SAAM,IAAI,MAAM,KAAK,UAAU,EAAE;QAChC,OAAO,IAAA,2BAAY,EAAC,OAAO,CAAC,CAAC;KAC9B;SAAM,IAAI,MAAM,KAAK,SAAS,EAAE;QAC/B,OAAO,IAAA,2BAAY,EAAC,OAAO,CAAC,CAAC;KAC9B;SAAM;QACL,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;KAClD;AACH,CAAC;AA5BD,oCA4BC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { ITerminal, NewlineKind } from '@rushstack/node-core-library';\n\nimport { ILocalizationFile } from './interfaces';\nimport { parseLocJson } from './parsers/parseLocJson';\nimport { parseResJson } from './parsers/parseResJson';\nimport { readResxAsLocFile } from './ResxReader';\n\n/**\n * @public\n */\nexport type ParserKind = 'resx' | 'loc.json' | 'resjson';\n\n/**\n * @public\n */\nexport interface IParseLocFileOptions {\n terminal: ITerminal;\n filePath: string;\n content: string;\n parser?: ParserKind;\n resxNewlineNormalization: NewlineKind | undefined;\n ignoreMissingResxComments: boolean | undefined;\n}\n\ninterface IParseCacheEntry {\n content: string;\n parsedFile: ILocalizationFile;\n}\n\nconst parseCache: Map<string, IParseCacheEntry> = new Map<string, IParseCacheEntry>();\n\nexport function selectParserByFilePath(filePath: string): ParserKind {\n if (/\\.resx$/i.test(filePath)) {\n return 'resx';\n } else if (/\\.(resx|loc)\\.json$/i.test(filePath)) {\n return 'loc.json';\n } else if (/\\.resjson$/i.test(filePath)) {\n return 'resjson';\n } else {\n throw new Error(`Unsupported file extension in file: ${filePath}`);\n }\n}\n\n/**\n * @public\n */\nexport function parseLocFile(options: IParseLocFileOptions): ILocalizationFile {\n const { parser = selectParserByFilePath(options.filePath) } = options;\n\n let parsedFile: ILocalizationFile;\n if (parser === 'resx') {\n const fileCacheKey: string = `${options.filePath}?${options.resxNewlineNormalization || 'none'}`;\n if (parseCache.has(fileCacheKey)) {\n const entry: IParseCacheEntry = parseCache.get(fileCacheKey)!;\n if (entry.content === options.content) {\n return entry.parsedFile;\n }\n }\n parsedFile = readResxAsLocFile(options.content, {\n terminal: options.terminal,\n resxFilePath: options.filePath,\n newlineNormalization: options.resxNewlineNormalization,\n warnOnMissingComment: !options.ignoreMissingResxComments\n });\n parseCache.set(fileCacheKey, { content: options.content, parsedFile });\n\n return parsedFile;\n } else if (parser === 'loc.json') {\n return parseLocJson(options);\n } else if (parser === 'resjson') {\n return parseResJson(options);\n } else {\n throw new Error(`Unsupported parser: ${parser}`);\n }\n}\n"]}
@@ -11,6 +11,8 @@ export interface ITypingsGeneratorOptions {
11
11
  globsToIgnore?: string[];
12
12
  resxNewlineNormalization?: NewlineKind | undefined;
13
13
  ignoreMissingResxComments?: boolean | undefined;
14
+ ignoreString?: (resxFilePath: string, stringName: string) => boolean;
15
+ processComment?: (comment: string | undefined, resxFilePath: string, stringName: string) => string | undefined;
14
16
  }
15
17
  /**
16
18
  * This is a simple tool that generates .d.ts files for .loc.json, .resx.json, .resjson, and .resx files.
@@ -1 +1 @@
1
- {"version":3,"file":"LocFileTypingsGenerator.d.ts","sourceRoot":"","sources":["../src/LocFileTypingsGenerator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,4BAA4B,EAAsB,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAKtE;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,wBAAwB,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACnD,yBAAyB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjD;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,4BAA4B;gBACpD,OAAO,EAAE,wBAAwB;CA2BrD"}
1
+ {"version":3,"file":"LocFileTypingsGenerator.d.ts","sourceRoot":"","sources":["../src/LocFileTypingsGenerator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,4BAA4B,EAAsB,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAKtE;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,wBAAwB,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACnD,yBAAyB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChD,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IACrE,cAAc,CAAC,EAAE,CACf,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,KACf,MAAM,GAAG,SAAS,CAAC;CACzB;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,4BAA4B;gBACpD,OAAO,EAAE,wBAAwB;CAkCrD"}
@@ -12,7 +12,11 @@ const LocFileParser_1 = require("./LocFileParser");
12
12
  */
13
13
  class LocFileTypingsGenerator extends typings_generator_1.StringValuesTypingsGenerator {
14
14
  constructor(options) {
15
- super(Object.assign(Object.assign({}, options), { fileExtensions: ['.resx', '.resx.json', '.loc.json', '.resjson'], parseAndGenerateTypings: (fileContents, filePath) => {
15
+ const { ignoreString, processComment } = options;
16
+ super({
17
+ ...options,
18
+ fileExtensions: ['.resx', '.resx.json', '.loc.json', '.resjson'],
19
+ parseAndGenerateTypings: (fileContents, filePath, resxFilePath) => {
16
20
  const locFileData = (0, LocFileParser_1.parseLocFile)({
17
21
  filePath: filePath,
18
22
  content: fileContents,
@@ -23,13 +27,20 @@ class LocFileTypingsGenerator extends typings_generator_1.StringValuesTypingsGen
23
27
  const typings = [];
24
28
  // eslint-disable-next-line guard-for-in
25
29
  for (const stringName in locFileData) {
26
- typings.push({
27
- exportName: stringName,
28
- comment: locFileData[stringName].comment
29
- });
30
+ if (!(ignoreString === null || ignoreString === void 0 ? void 0 : ignoreString(resxFilePath, stringName))) {
31
+ let comment = locFileData[stringName].comment;
32
+ if (processComment) {
33
+ comment = processComment(comment, resxFilePath, stringName);
34
+ }
35
+ typings.push({
36
+ exportName: stringName,
37
+ comment
38
+ });
39
+ }
30
40
  }
31
41
  return { typings };
32
- } }));
42
+ }
43
+ });
33
44
  }
34
45
  }
35
46
  exports.LocFileTypingsGenerator = LocFileTypingsGenerator;
@@ -1 +1 @@
1
- {"version":3,"file":"LocFileTypingsGenerator.js","sourceRoot":"","sources":["../src/LocFileTypingsGenerator.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAAgG;AAIhG,mDAA+C;AAe/C;;;;GAIG;AACH,MAAa,uBAAwB,SAAQ,gDAA4B;IACvE,YAAmB,OAAiC;QAClD,KAAK,iCACA,OAAO,KACV,cAAc,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,CAAC,EAChE,uBAAuB,EAAE,CAAC,YAAoB,EAAE,QAAgB,EAAE,EAAE;gBAClE,MAAM,WAAW,GAAsB,IAAA,4BAAY,EAAC;oBAClD,QAAQ,EAAE,QAAQ;oBAClB,OAAO,EAAE,YAAY;oBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAS;oBACjC,wBAAwB,EAAE,OAAO,CAAC,wBAAwB;oBAC1D,yBAAyB,EAAE,OAAO,CAAC,yBAAyB;iBAC7D,CAAC,CAAC;gBAEH,MAAM,OAAO,GAAyB,EAAE,CAAC;gBAEzC,wCAAwC;gBACxC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;oBACpC,OAAO,CAAC,IAAI,CAAC;wBACX,UAAU,EAAE,UAAU;wBACtB,OAAO,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,OAAO;qBACzC,CAAC,CAAC;iBACJ;gBAED,OAAO,EAAE,OAAO,EAAE,CAAC;YACrB,CAAC,IACD,CAAC;IACL,CAAC;CACF;AA5BD,0DA4BC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { StringValuesTypingsGenerator, IStringValueTyping } from '@rushstack/typings-generator';\nimport { ITerminal, NewlineKind } from '@rushstack/node-core-library';\n\nimport { ILocalizationFile } from './interfaces';\nimport { parseLocFile } from './LocFileParser';\n\n/**\n * @public\n */\nexport interface ITypingsGeneratorOptions {\n srcFolder: string;\n generatedTsFolder: string;\n terminal?: ITerminal;\n exportAsDefault?: boolean;\n globsToIgnore?: string[];\n resxNewlineNormalization?: NewlineKind | undefined;\n ignoreMissingResxComments?: boolean | undefined;\n}\n\n/**\n * This is a simple tool that generates .d.ts files for .loc.json, .resx.json, .resjson, and .resx files.\n *\n * @public\n */\nexport class LocFileTypingsGenerator extends StringValuesTypingsGenerator {\n public constructor(options: ITypingsGeneratorOptions) {\n super({\n ...options,\n fileExtensions: ['.resx', '.resx.json', '.loc.json', '.resjson'],\n parseAndGenerateTypings: (fileContents: string, filePath: string) => {\n const locFileData: ILocalizationFile = parseLocFile({\n filePath: filePath,\n content: fileContents,\n terminal: this._options.terminal!,\n resxNewlineNormalization: options.resxNewlineNormalization,\n ignoreMissingResxComments: options.ignoreMissingResxComments\n });\n\n const typings: IStringValueTyping[] = [];\n\n // eslint-disable-next-line guard-for-in\n for (const stringName in locFileData) {\n typings.push({\n exportName: stringName,\n comment: locFileData[stringName].comment\n });\n }\n\n return { typings };\n }\n });\n }\n}\n"]}
1
+ {"version":3,"file":"LocFileTypingsGenerator.js","sourceRoot":"","sources":["../src/LocFileTypingsGenerator.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAAgG;AAIhG,mDAA+C;AAqB/C;;;;GAIG;AACH,MAAa,uBAAwB,SAAQ,gDAA4B;IACvE,YAAmB,OAAiC;QAClD,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;QACjD,KAAK,CAAC;YACJ,GAAG,OAAO;YACV,cAAc,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,CAAC;YAChE,uBAAuB,EAAE,CAAC,YAAoB,EAAE,QAAgB,EAAE,YAAoB,EAAE,EAAE;gBACxF,MAAM,WAAW,GAAsB,IAAA,4BAAY,EAAC;oBAClD,QAAQ,EAAE,QAAQ;oBAClB,OAAO,EAAE,YAAY;oBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAS;oBACjC,wBAAwB,EAAE,OAAO,CAAC,wBAAwB;oBAC1D,yBAAyB,EAAE,OAAO,CAAC,yBAAyB;iBAC7D,CAAC,CAAC;gBAEH,MAAM,OAAO,GAAyB,EAAE,CAAC;gBAEzC,wCAAwC;gBACxC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;oBACpC,IAAI,CAAC,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAG,YAAY,EAAE,UAAU,CAAC,CAAA,EAAE;wBAC7C,IAAI,OAAO,GAAuB,WAAW,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC;wBAClE,IAAI,cAAc,EAAE;4BAClB,OAAO,GAAG,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;yBAC7D;wBACD,OAAO,CAAC,IAAI,CAAC;4BACX,UAAU,EAAE,UAAU;4BACtB,OAAO;yBACR,CAAC,CAAC;qBACJ;iBACF;gBAED,OAAO,EAAE,OAAO,EAAE,CAAC;YACrB,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF;AAnCD,0DAmCC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { StringValuesTypingsGenerator, IStringValueTyping } from '@rushstack/typings-generator';\nimport { ITerminal, NewlineKind } from '@rushstack/node-core-library';\n\nimport { ILocalizationFile } from './interfaces';\nimport { parseLocFile } from './LocFileParser';\n\n/**\n * @public\n */\nexport interface ITypingsGeneratorOptions {\n srcFolder: string;\n generatedTsFolder: string;\n terminal?: ITerminal;\n exportAsDefault?: boolean;\n globsToIgnore?: string[];\n resxNewlineNormalization?: NewlineKind | undefined;\n ignoreMissingResxComments?: boolean | undefined;\n ignoreString?: (resxFilePath: string, stringName: string) => boolean;\n processComment?: (\n comment: string | undefined,\n resxFilePath: string,\n stringName: string\n ) => string | undefined;\n}\n\n/**\n * This is a simple tool that generates .d.ts files for .loc.json, .resx.json, .resjson, and .resx files.\n *\n * @public\n */\nexport class LocFileTypingsGenerator extends StringValuesTypingsGenerator {\n public constructor(options: ITypingsGeneratorOptions) {\n const { ignoreString, processComment } = options;\n super({\n ...options,\n fileExtensions: ['.resx', '.resx.json', '.loc.json', '.resjson'],\n parseAndGenerateTypings: (fileContents: string, filePath: string, resxFilePath: string) => {\n const locFileData: ILocalizationFile = parseLocFile({\n filePath: filePath,\n content: fileContents,\n terminal: this._options.terminal!,\n resxNewlineNormalization: options.resxNewlineNormalization,\n ignoreMissingResxComments: options.ignoreMissingResxComments\n });\n\n const typings: IStringValueTyping[] = [];\n\n // eslint-disable-next-line guard-for-in\n for (const stringName in locFileData) {\n if (!ignoreString?.(resxFilePath, stringName)) {\n let comment: string | undefined = locFileData[stringName].comment;\n if (processComment) {\n comment = processComment(comment, resxFilePath, stringName);\n }\n typings.push({\n exportName: stringName,\n comment\n });\n }\n }\n\n return { typings };\n }\n });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"Pseudolocalization.d.ts","sourceRoot":"","sources":["../src/Pseudolocalization.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAUzF"}
1
+ {"version":3,"file":"Pseudolocalization.d.ts","sourceRoot":"","sources":["../src/Pseudolocalization.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AASpD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAkBzF"}
@@ -6,17 +6,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
6
6
  };
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
8
  exports.getPseudolocalizer = void 0;
9
- const decache_1 = __importDefault(require("decache"));
9
+ const vm_1 = __importDefault(require("vm"));
10
+ const node_core_library_1 = require("@rushstack/node-core-library");
11
+ const pseudolocalePath = require.resolve('pseudolocale/pseudolocale.min.js');
10
12
  /**
11
13
  * Get a function that pseudolocalizes a string.
12
14
  *
13
15
  * @public
14
16
  */
15
17
  function getPseudolocalizer(options) {
16
- // pseudolocale maintains static state, so we need to load it as isolated modules
17
- (0, decache_1.default)('pseudolocale');
18
- const pseudolocale = require('pseudolocale'); // eslint-disable-line
19
- pseudolocale.option = Object.assign(Object.assign({}, pseudolocale.option), options);
18
+ const pseudolocaleCode = node_core_library_1.FileSystem.readFile(pseudolocalePath);
19
+ const context = {
20
+ pseudolocale: undefined
21
+ };
22
+ // Load pseudolocale in an isolated context because the configuration for is stored on a singleton
23
+ vm_1.default.runInNewContext(pseudolocaleCode, context);
24
+ const { pseudolocale } = context;
25
+ if (!pseudolocale) {
26
+ throw new Error(`Failed to load pseudolocale module`);
27
+ }
28
+ Object.assign(pseudolocale.option, options);
29
+ // `pseudolocale.str` captures `pseudolocale` in its closure and refers to `pseudolocale.option`.
20
30
  return pseudolocale.str;
21
31
  }
22
32
  exports.getPseudolocalizer = getPseudolocalizer;
@@ -1 +1 @@
1
- {"version":3,"file":"Pseudolocalization.js","sourceRoot":"","sources":["../src/Pseudolocalization.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;;;;AAE3D,sDAA8B;AAI9B;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,OAA6B;IAC9D,iFAAiF;IACjF,IAAA,iBAAO,EAAC,cAAc,CAAC,CAAC;IACxB,MAAM,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,sBAAsB;IAEpE,YAAY,CAAC,MAAM,mCACd,YAAY,CAAC,MAAM,GACnB,OAAO,CACX,CAAC;IACF,OAAO,YAAY,CAAC,GAAG,CAAC;AAC1B,CAAC;AAVD,gDAUC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport decache from 'decache';\n\nimport { IPseudolocaleOptions } from './interfaces';\n\n/**\n * Get a function that pseudolocalizes a string.\n *\n * @public\n */\nexport function getPseudolocalizer(options: IPseudolocaleOptions): (str: string) => string {\n // pseudolocale maintains static state, so we need to load it as isolated modules\n decache('pseudolocale');\n const pseudolocale = require('pseudolocale'); // eslint-disable-line\n\n pseudolocale.option = {\n ...pseudolocale.option,\n ...options\n };\n return pseudolocale.str;\n}\n"]}
1
+ {"version":3,"file":"Pseudolocalization.js","sourceRoot":"","sources":["../src/Pseudolocalization.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;;;;AAE3D,4CAAoB;AACpB,oEAA0D;AAI1D,MAAM,gBAAgB,GAAW,OAAO,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;AAOrF;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,OAA6B;IAC9D,MAAM,gBAAgB,GAAW,8BAAU,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACvE,MAAM,OAAO,GAET;QACF,YAAY,EAAE,SAAS;KACxB,CAAC;IAEF,kGAAkG;IAClG,YAAE,CAAC,eAAe,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IACjC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;KACvD;IAED,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,iGAAiG;IACjG,OAAO,YAAY,CAAC,GAAG,CAAC;AAC1B,CAAC;AAlBD,gDAkBC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport vm from 'vm';\nimport { FileSystem } from '@rushstack/node-core-library';\n\nimport { IPseudolocaleOptions } from './interfaces';\n\nconst pseudolocalePath: string = require.resolve('pseudolocale/pseudolocale.min.js');\n\ninterface IPseudolocale {\n option: IPseudolocaleOptions;\n str(str: string): string;\n}\n\n/**\n * Get a function that pseudolocalizes a string.\n *\n * @public\n */\nexport function getPseudolocalizer(options: IPseudolocaleOptions): (str: string) => string {\n const pseudolocaleCode: string = FileSystem.readFile(pseudolocalePath);\n const context: {\n pseudolocale: IPseudolocale | undefined;\n } = {\n pseudolocale: undefined\n };\n\n // Load pseudolocale in an isolated context because the configuration for is stored on a singleton\n vm.runInNewContext(pseudolocaleCode, context);\n const { pseudolocale } = context;\n if (!pseudolocale) {\n throw new Error(`Failed to load pseudolocale module`);\n }\n\n Object.assign(pseudolocale.option, options);\n // `pseudolocale.str` captures `pseudolocale` in its closure and refers to `pseudolocale.option`.\n return pseudolocale.str;\n}\n"]}
package/lib/ResxReader.js CHANGED
@@ -30,8 +30,11 @@ function readResxAsLocFile(resxContents, options) {
30
30
  _logWithLocation(writeWarning, message, filePath, line, position);
31
31
  }
32
32
  };
33
- return _readResxAsLocFileInternal(Object.assign(Object.assign({}, options), { resxContents,
34
- loggingFunctions }));
33
+ return _readResxAsLocFileInternal({
34
+ ...options,
35
+ resxContents,
36
+ loggingFunctions
37
+ });
35
38
  }
36
39
  exports.readResxAsLocFile = readResxAsLocFile;
37
40
  function _readResxAsLocFileInternal(options) {
@@ -1 +1 @@
1
- {"version":3,"file":"ResxReader.js","sourceRoot":"","sources":["../src/ResxReader.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { FileSystem, ITerminal, Text, NewlineKind } from '@rushstack/node-core-library';\nimport { XmlDocument, XmlElement } from 'xmldoc';\n\nimport { ILocalizedString, ILocalizationFile } from './interfaces';\n\nconst STRING_NAME_RESX: RegExp = /^[A-z_$][A-z0-9_$]*$/;\n\n/**\n * @public\n */\nexport interface IResxReaderOptions {\n resxFilePath: string;\n terminal: ITerminal;\n newlineNormalization: NewlineKind | undefined;\n warnOnMissingComment: boolean;\n}\n\ninterface ILoggingFunctions {\n logError: (message: string) => void;\n logWarning: (message: string) => void;\n logFileError: (message: string, filePath: string, line?: number, position?: number) => void;\n logFileWarning: (message: string, filePath: string, line?: number, position?: number) => void;\n}\n\ninterface IResxReaderOptionsInternal extends Omit<IResxReaderOptions, 'terminal'> {\n resxContents: string;\n loggingFunctions: ILoggingFunctions;\n}\n\n/**\n * @public\n */\nexport function readResxFileAsLocFile(options: IResxReaderOptions): ILocalizationFile {\n const resxContents: string = FileSystem.readFile(options.resxFilePath);\n return readResxAsLocFile(resxContents, options);\n}\n\n/**\n * @public\n */\nexport function readResxAsLocFile(resxContents: string, options: IResxReaderOptions): ILocalizationFile {\n const writeError: (message: string) => void = options.terminal.writeErrorLine.bind(options.terminal);\n const writeWarning: (message: string) => void = options.terminal.writeWarningLine.bind(options.terminal);\n const loggingFunctions: ILoggingFunctions = {\n logError: (message: string) => writeError(message),\n logWarning: (message: string) => writeWarning(message),\n logFileError: (message: string, filePath: string, line?: number, position?: number) => {\n _logWithLocation(writeError, message, filePath, line, position);\n },\n logFileWarning: (message: string, filePath: string, line?: number, position?: number) => {\n _logWithLocation(writeWarning, message, filePath, line, position);\n }\n };\n\n return _readResxAsLocFileInternal({\n ...options,\n resxContents,\n loggingFunctions\n });\n}\n\nfunction _readResxAsLocFileInternal(options: IResxReaderOptionsInternal): ILocalizationFile {\n const xmlDocument: XmlDocument = new XmlDocument(options.resxContents);\n\n if (xmlDocument.name !== 'root') {\n _logErrorWithLocation(\n options,\n `Expected RESX to have a \"root\" element, found \"${xmlDocument.name}\"`,\n xmlDocument\n );\n }\n\n const locFile: ILocalizationFile = {};\n\n for (const childNode of xmlDocument.children) {\n switch (childNode.type) {\n case 'element': {\n switch (childNode.name) {\n case 'data': {\n const stringName: string = childNode.attr.name;\n if (!stringName) {\n _logErrorWithLocation(options, 'Unexpected missing or empty string name', childNode);\n } else if (!STRING_NAME_RESX.test(stringName)) {\n _logErrorWithLocation(options, `Invalid string name \"${stringName}\"`, childNode);\n } else {\n if (locFile.hasOwnProperty(stringName)) {\n _logErrorWithLocation(options, `Duplicate string value \"${stringName}\"`, childNode);\n }\n\n const locString: ILocalizedString | undefined = _readDataElement(options, childNode);\n\n if (locString) {\n locFile[stringName] = locString;\n }\n }\n\n break;\n }\n\n // Other allowed elements\n case 'xsd:schema':\n case 'resheader':\n break;\n\n default:\n _logErrorWithLocation(options, `Unexpected RESX element ${childNode.name}`, childNode);\n }\n\n break;\n }\n\n case 'text': {\n if (childNode.text.trim() !== '') {\n _logErrorWithLocation(options, 'Found unexpected non-empty text node in RESX');\n }\n\n break;\n }\n\n case 'comment':\n break;\n\n default:\n _logErrorWithLocation(options, `Unexpected ${childNode.type} child in RESX`);\n break;\n }\n }\n\n return locFile;\n}\n\nfunction _readDataElement(\n options: IResxReaderOptionsInternal,\n dataElement: XmlElement\n): ILocalizedString | undefined {\n let foundCommentElement: boolean = false;\n let foundValueElement: boolean = false;\n let comment: string | undefined = undefined;\n let value: string | undefined = undefined;\n\n for (const childNode of dataElement.children) {\n switch (childNode.type) {\n case 'element': {\n switch (childNode.name) {\n case 'value': {\n if (foundValueElement) {\n _logErrorWithLocation(options, 'Duplicate <value> element found', childNode);\n } else {\n foundValueElement = true;\n value = _readTextElement(options, childNode);\n if (value && options.newlineNormalization) {\n value = Text.convertTo(value, options.newlineNormalization);\n }\n }\n\n break;\n }\n\n case 'comment': {\n if (foundCommentElement) {\n _logErrorWithLocation(options, 'Duplicate <comment> element found', childNode);\n } else {\n foundCommentElement = true;\n comment = _readTextElement(options, childNode);\n }\n\n break;\n }\n\n default:\n _logErrorWithLocation(options, `Unexpected RESX element ${childNode.name}`, childNode);\n break;\n }\n\n break;\n }\n\n case 'text': {\n if (childNode.text.trim() !== '') {\n _logErrorWithLocation(\n options,\n 'Found unexpected non-empty text node in RESX <data> element',\n dataElement\n );\n }\n\n break;\n }\n\n case 'comment':\n break;\n\n default:\n _logErrorWithLocation(\n options,\n `Unexpected ${childNode.type} child in RESX <data> element`,\n dataElement\n );\n }\n }\n\n if (!foundValueElement) {\n _logErrorWithLocation(options, 'Missing string value in <data> element', dataElement);\n } else {\n if (comment === undefined && options.warnOnMissingComment) {\n _logWarningWithLocation(options, 'Missing string comment in <data> element', dataElement);\n }\n\n return {\n value: value || '',\n comment\n };\n }\n}\n\nfunction _readTextElement(options: IResxReaderOptionsInternal, element: XmlElement): string | undefined {\n let foundText: string | undefined = undefined;\n\n for (const childNode of element.children) {\n switch (childNode.type) {\n case 'cdata':\n case 'text': {\n if (foundText !== undefined) {\n _logErrorWithLocation(options, 'More than one child node found containing text content', element);\n break;\n }\n\n foundText = childNode.type === 'text' ? childNode.text : childNode.cdata;\n break;\n }\n\n case 'comment':\n break;\n\n case 'element':\n _logErrorWithLocation(options, `Unexpected element`, childNode);\n break;\n\n default:\n _logErrorWithLocation(options, `Unexpected ${element.type} child`, element);\n break;\n }\n }\n\n return foundText;\n}\n\nfunction _logErrorWithLocation(\n options: IResxReaderOptionsInternal,\n message: string,\n element?: XmlElement | XmlDocument\n): void {\n if (element) {\n options.loggingFunctions.logFileError(\n message,\n options.resxFilePath,\n element.line + 1,\n element.column + 1\n );\n } else {\n options.loggingFunctions.logFileError(message, options.resxFilePath);\n }\n}\n\nfunction _logWarningWithLocation(\n options: IResxReaderOptionsInternal,\n message: string,\n element?: XmlElement | XmlDocument\n): void {\n if (element) {\n options.loggingFunctions.logFileWarning(\n message,\n options.resxFilePath,\n element.line + 1,\n element.column + 1\n );\n } else {\n options.loggingFunctions.logFileWarning(message, options.resxFilePath);\n }\n}\n\nfunction _logWithLocation(\n loggingFn: (message: string) => void,\n message: string,\n filePath: string,\n line?: number,\n position?: number\n): void {\n let location: string;\n if (position !== undefined) {\n location = `${filePath}(${line},${position})`;\n } else if (line !== undefined) {\n location = `${filePath}(${line})`;\n } else {\n location = filePath;\n }\n\n loggingFn(`${location}: ${message}`);\n}\n"]}
1
+ {"version":3,"file":"ResxReader.js","sourceRoot":"","sources":["../src/ResxReader.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { FileSystem, ITerminal, Text, NewlineKind } from '@rushstack/node-core-library';\nimport { XmlDocument, XmlElement } from 'xmldoc';\n\nimport { ILocalizedString, ILocalizationFile } from './interfaces';\n\nconst STRING_NAME_RESX: RegExp = /^[A-z_$][A-z0-9_$]*$/;\n\n/**\n * @public\n */\nexport interface IResxReaderOptions {\n resxFilePath: string;\n terminal: ITerminal;\n newlineNormalization: NewlineKind | undefined;\n warnOnMissingComment: boolean;\n}\n\ninterface ILoggingFunctions {\n logError: (message: string) => void;\n logWarning: (message: string) => void;\n logFileError: (message: string, filePath: string, line?: number, position?: number) => void;\n logFileWarning: (message: string, filePath: string, line?: number, position?: number) => void;\n}\n\ninterface IResxReaderOptionsInternal extends Omit<IResxReaderOptions, 'terminal'> {\n resxContents: string;\n loggingFunctions: ILoggingFunctions;\n}\n\n/**\n * @public\n */\nexport function readResxFileAsLocFile(options: IResxReaderOptions): ILocalizationFile {\n const resxContents: string = FileSystem.readFile(options.resxFilePath);\n return readResxAsLocFile(resxContents, options);\n}\n\n/**\n * @public\n */\nexport function readResxAsLocFile(resxContents: string, options: IResxReaderOptions): ILocalizationFile {\n const writeError: (message: string) => void = options.terminal.writeErrorLine.bind(options.terminal);\n const writeWarning: (message: string) => void = options.terminal.writeWarningLine.bind(options.terminal);\n const loggingFunctions: ILoggingFunctions = {\n logError: (message: string) => writeError(message),\n logWarning: (message: string) => writeWarning(message),\n logFileError: (message: string, filePath: string, line?: number, position?: number) => {\n _logWithLocation(writeError, message, filePath, line, position);\n },\n logFileWarning: (message: string, filePath: string, line?: number, position?: number) => {\n _logWithLocation(writeWarning, message, filePath, line, position);\n }\n };\n\n return _readResxAsLocFileInternal({\n ...options,\n resxContents,\n loggingFunctions\n });\n}\n\nfunction _readResxAsLocFileInternal(options: IResxReaderOptionsInternal): ILocalizationFile {\n const xmlDocument: XmlDocument = new XmlDocument(options.resxContents);\n\n if (xmlDocument.name !== 'root') {\n _logErrorWithLocation(\n options,\n `Expected RESX to have a \"root\" element, found \"${xmlDocument.name}\"`,\n xmlDocument\n );\n }\n\n const locFile: ILocalizationFile = {};\n\n for (const childNode of xmlDocument.children) {\n switch (childNode.type) {\n case 'element': {\n switch (childNode.name) {\n case 'data': {\n const stringName: string = childNode.attr.name;\n if (!stringName) {\n _logErrorWithLocation(options, 'Unexpected missing or empty string name', childNode);\n } else if (!STRING_NAME_RESX.test(stringName)) {\n _logErrorWithLocation(options, `Invalid string name \"${stringName}\"`, childNode);\n } else {\n if (locFile.hasOwnProperty(stringName)) {\n _logErrorWithLocation(options, `Duplicate string value \"${stringName}\"`, childNode);\n }\n\n const locString: ILocalizedString | undefined = _readDataElement(options, childNode);\n\n if (locString) {\n locFile[stringName] = locString;\n }\n }\n\n break;\n }\n\n // Other allowed elements\n case 'xsd:schema':\n case 'resheader':\n break;\n\n default:\n _logErrorWithLocation(options, `Unexpected RESX element ${childNode.name}`, childNode);\n }\n\n break;\n }\n\n case 'text': {\n if (childNode.text.trim() !== '') {\n _logErrorWithLocation(options, 'Found unexpected non-empty text node in RESX');\n }\n\n break;\n }\n\n case 'comment':\n break;\n\n default:\n _logErrorWithLocation(options, `Unexpected ${childNode.type} child in RESX`);\n break;\n }\n }\n\n return locFile;\n}\n\nfunction _readDataElement(\n options: IResxReaderOptionsInternal,\n dataElement: XmlElement\n): ILocalizedString | undefined {\n let foundCommentElement: boolean = false;\n let foundValueElement: boolean = false;\n let comment: string | undefined = undefined;\n let value: string | undefined = undefined;\n\n for (const childNode of dataElement.children) {\n switch (childNode.type) {\n case 'element': {\n switch (childNode.name) {\n case 'value': {\n if (foundValueElement) {\n _logErrorWithLocation(options, 'Duplicate <value> element found', childNode);\n } else {\n foundValueElement = true;\n value = _readTextElement(options, childNode);\n if (value && options.newlineNormalization) {\n value = Text.convertTo(value, options.newlineNormalization);\n }\n }\n\n break;\n }\n\n case 'comment': {\n if (foundCommentElement) {\n _logErrorWithLocation(options, 'Duplicate <comment> element found', childNode);\n } else {\n foundCommentElement = true;\n comment = _readTextElement(options, childNode);\n }\n\n break;\n }\n\n default:\n _logErrorWithLocation(options, `Unexpected RESX element ${childNode.name}`, childNode);\n break;\n }\n\n break;\n }\n\n case 'text': {\n if (childNode.text.trim() !== '') {\n _logErrorWithLocation(\n options,\n 'Found unexpected non-empty text node in RESX <data> element',\n dataElement\n );\n }\n\n break;\n }\n\n case 'comment':\n break;\n\n default:\n _logErrorWithLocation(\n options,\n `Unexpected ${childNode.type} child in RESX <data> element`,\n dataElement\n );\n }\n }\n\n if (!foundValueElement) {\n _logErrorWithLocation(options, 'Missing string value in <data> element', dataElement);\n } else {\n if (comment === undefined && options.warnOnMissingComment) {\n _logWarningWithLocation(options, 'Missing string comment in <data> element', dataElement);\n }\n\n return {\n value: value || '',\n comment\n };\n }\n}\n\nfunction _readTextElement(options: IResxReaderOptionsInternal, element: XmlElement): string | undefined {\n let foundText: string | undefined = undefined;\n\n for (const childNode of element.children) {\n switch (childNode.type) {\n case 'cdata':\n case 'text': {\n if (foundText !== undefined) {\n _logErrorWithLocation(options, 'More than one child node found containing text content', element);\n break;\n }\n\n foundText = childNode.type === 'text' ? childNode.text : childNode.cdata;\n break;\n }\n\n case 'comment':\n break;\n\n case 'element':\n _logErrorWithLocation(options, `Unexpected element`, childNode);\n break;\n\n default:\n _logErrorWithLocation(options, `Unexpected ${element.type} child`, element);\n break;\n }\n }\n\n return foundText;\n}\n\nfunction _logErrorWithLocation(\n options: IResxReaderOptionsInternal,\n message: string,\n element?: XmlElement | XmlDocument\n): void {\n if (element) {\n options.loggingFunctions.logFileError(\n message,\n options.resxFilePath,\n element.line + 1,\n element.column + 1\n );\n } else {\n options.loggingFunctions.logFileError(message, options.resxFilePath);\n }\n}\n\nfunction _logWarningWithLocation(\n options: IResxReaderOptionsInternal,\n message: string,\n element?: XmlElement | XmlDocument\n): void {\n if (element) {\n options.loggingFunctions.logFileWarning(\n message,\n options.resxFilePath,\n element.line + 1,\n element.column + 1\n );\n } else {\n options.loggingFunctions.logFileWarning(message, options.resxFilePath);\n }\n}\n\nfunction _logWithLocation(\n loggingFn: (message: string) => void,\n message: string,\n filePath: string,\n line?: number,\n position?: number\n): void {\n let location: string;\n if (position !== undefined) {\n location = `${filePath}(${line},${position})`;\n } else if (line !== undefined) {\n location = `${filePath}(${line})`;\n } else {\n location = filePath;\n }\n\n loggingFn(`${location}: ${message}`);\n}\n"]}
package/lib/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- export { ILocalizationFile, ILocalizedString, IPseudolocaleOptions } from './interfaces';
2
- export { parseLocFile, IParseLocFileOptions } from './LocFileParser';
1
+ export type { ILocalizationFile, ILocalizedString, IPseudolocaleOptions, IParseFileOptions } from './interfaces';
2
+ export { parseLocJson } from './parsers/parseLocJson';
3
+ export { parseResJson } from './parsers/parseResJson';
4
+ export { parseLocFile, IParseLocFileOptions, ParserKind } from './LocFileParser';
3
5
  export { ITypingsGeneratorOptions, LocFileTypingsGenerator as TypingsGenerator } from './LocFileTypingsGenerator';
4
6
  export { readResxFileAsLocFile, readResxAsLocFile, IResxReaderOptions } from './ResxReader';
5
7
  export { getPseudolocalizer } from './Pseudolocalization';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EACL,wBAAwB,EACxB,uBAAuB,IAAI,gBAAgB,EAC5C,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,EACL,wBAAwB,EACxB,uBAAuB,IAAI,gBAAgB,EAC5C,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}
package/lib/index.js CHANGED
@@ -2,7 +2,11 @@
2
2
  // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3
3
  // See LICENSE in the project root for license information.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.getPseudolocalizer = exports.readResxAsLocFile = exports.readResxFileAsLocFile = exports.TypingsGenerator = exports.parseLocFile = void 0;
5
+ exports.getPseudolocalizer = exports.readResxAsLocFile = exports.readResxFileAsLocFile = exports.TypingsGenerator = exports.parseLocFile = exports.parseResJson = exports.parseLocJson = void 0;
6
+ var parseLocJson_1 = require("./parsers/parseLocJson");
7
+ Object.defineProperty(exports, "parseLocJson", { enumerable: true, get: function () { return parseLocJson_1.parseLocJson; } });
8
+ var parseResJson_1 = require("./parsers/parseResJson");
9
+ Object.defineProperty(exports, "parseResJson", { enumerable: true, get: function () { return parseResJson_1.parseResJson; } });
6
10
  var LocFileParser_1 = require("./LocFileParser");
7
11
  Object.defineProperty(exports, "parseLocFile", { enumerable: true, get: function () { return LocFileParser_1.parseLocFile; } });
8
12
  var LocFileTypingsGenerator_1 = require("./LocFileTypingsGenerator");
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAG3D,iDAAqE;AAA5D,6GAAA,YAAY,OAAA;AACrB,qEAGmC;AADjC,2HAAA,uBAAuB,OAAoB;AAE7C,2CAA4F;AAAnF,mHAAA,qBAAqB,OAAA;AAAE,+GAAA,iBAAiB,OAAA;AACjD,2DAA0D;AAAjD,wHAAA,kBAAkB,OAAA","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nexport { ILocalizationFile, ILocalizedString, IPseudolocaleOptions } from './interfaces';\nexport { parseLocFile, IParseLocFileOptions } from './LocFileParser';\nexport {\n ITypingsGeneratorOptions,\n LocFileTypingsGenerator as TypingsGenerator\n} from './LocFileTypingsGenerator';\nexport { readResxFileAsLocFile, readResxAsLocFile, IResxReaderOptions } from './ResxReader';\nexport { getPseudolocalizer } from './Pseudolocalization';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAQ3D,uDAAsD;AAA7C,4GAAA,YAAY,OAAA;AACrB,uDAAsD;AAA7C,4GAAA,YAAY,OAAA;AACrB,iDAAiF;AAAxE,6GAAA,YAAY,OAAA;AACrB,qEAGmC;AADjC,2HAAA,uBAAuB,OAAoB;AAE7C,2CAA4F;AAAnF,mHAAA,qBAAqB,OAAA;AAAE,+GAAA,iBAAiB,OAAA;AACjD,2DAA0D;AAAjD,wHAAA,kBAAkB,OAAA","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nexport type {\n ILocalizationFile,\n ILocalizedString,\n IPseudolocaleOptions,\n IParseFileOptions\n} from './interfaces';\nexport { parseLocJson } from './parsers/parseLocJson';\nexport { parseResJson } from './parsers/parseResJson';\nexport { parseLocFile, IParseLocFileOptions, ParserKind } from './LocFileParser';\nexport {\n ITypingsGeneratorOptions,\n LocFileTypingsGenerator as TypingsGenerator\n} from './LocFileTypingsGenerator';\nexport { readResxFileAsLocFile, readResxAsLocFile, IResxReaderOptions } from './ResxReader';\nexport { getPseudolocalizer } from './Pseudolocalization';\n"]}
@@ -28,4 +28,11 @@ export interface ILocalizedString {
28
28
  value: string;
29
29
  comment?: string;
30
30
  }
31
+ /**
32
+ * @public
33
+ */
34
+ export interface IParseFileOptions {
35
+ content: string;
36
+ filePath: string;
37
+ }
31
38
  //# sourceMappingURL=interfaces.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Options for the pseudolocale library.\n *\n * @internalRemarks\n * Eventually this should be replaced with DefinitelyTyped types.\n *\n * @public\n */\nexport interface IPseudolocaleOptions {\n prepend?: string;\n append?: string;\n delimiter?: string;\n startDelimiter?: string;\n endDelimiter?: string;\n extend?: number;\n override?: string;\n}\n\n/**\n * @public\n */\nexport interface ILocalizationFile {\n [stringName: string]: ILocalizedString;\n}\n\n/**\n * @public\n */\nexport interface ILocalizedString {\n value: string;\n comment?: string;\n}\n"]}
1
+ {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Options for the pseudolocale library.\n *\n * @internalRemarks\n * Eventually this should be replaced with DefinitelyTyped types.\n *\n * @public\n */\nexport interface IPseudolocaleOptions {\n prepend?: string;\n append?: string;\n delimiter?: string;\n startDelimiter?: string;\n endDelimiter?: string;\n extend?: number;\n override?: string;\n}\n\n/**\n * @public\n */\nexport interface ILocalizationFile {\n [stringName: string]: ILocalizedString;\n}\n\n/**\n * @public\n */\nexport interface ILocalizedString {\n value: string;\n comment?: string;\n}\n\n/**\n * @public\n */\nexport interface IParseFileOptions {\n content: string;\n filePath: string;\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import { ILocalizationFile, IParseFileOptions } from '../interfaces';
2
+ /**
3
+ * @public
4
+ */
5
+ export declare function parseLocJson(options: IParseFileOptions): ILocalizationFile;
6
+ //# sourceMappingURL=parseLocJson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseLocJson.d.ts","sourceRoot":"","sources":["../../src/parsers/parseLocJson.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAKrE;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,CAQ1E"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3
+ // See LICENSE in the project root for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.parseLocJson = void 0;
6
+ const path_1 = require("path");
7
+ const node_core_library_1 = require("@rushstack/node-core-library");
8
+ const LOC_JSON_SCHEMA_PATH = (0, path_1.resolve)(__dirname, '../schemas/locJson.schema.json');
9
+ const LOC_JSON_SCHEMA = node_core_library_1.JsonSchema.fromFile(LOC_JSON_SCHEMA_PATH);
10
+ /**
11
+ * @public
12
+ */
13
+ function parseLocJson(options) {
14
+ const parsedFile = node_core_library_1.JsonFile.parseString(options.content);
15
+ try {
16
+ LOC_JSON_SCHEMA.validateObject(parsedFile, options.filePath);
17
+ }
18
+ catch (e) {
19
+ throw new Error(`The loc file is invalid. Error: ${e}`);
20
+ }
21
+ return parsedFile;
22
+ }
23
+ exports.parseLocJson = parseLocJson;
24
+ //# sourceMappingURL=parseLocJson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseLocJson.js","sourceRoot":"","sources":["../../src/parsers/parseLocJson.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,+BAA+B;AAE/B,oEAAoE;AAIpE,MAAM,oBAAoB,GAAW,IAAA,cAAO,EAAC,SAAS,EAAE,gCAAgC,CAAC,CAAC;AAC1F,MAAM,eAAe,GAAe,8BAAU,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;AAE9E;;GAEG;AACH,SAAgB,YAAY,CAAC,OAA0B;IACrD,MAAM,UAAU,GAAsB,4BAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5E,IAAI;QACF,eAAe,CAAC,cAAc,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;KAC9D;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,EAAE,CAAC,CAAC;KACzD;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AARD,oCAQC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { resolve } from 'path';\n\nimport { JsonFile, JsonSchema } from '@rushstack/node-core-library';\n\nimport { ILocalizationFile, IParseFileOptions } from '../interfaces';\n\nconst LOC_JSON_SCHEMA_PATH: string = resolve(__dirname, '../schemas/locJson.schema.json');\nconst LOC_JSON_SCHEMA: JsonSchema = JsonSchema.fromFile(LOC_JSON_SCHEMA_PATH);\n\n/**\n * @public\n */\nexport function parseLocJson(options: IParseFileOptions): ILocalizationFile {\n const parsedFile: ILocalizationFile = JsonFile.parseString(options.content);\n try {\n LOC_JSON_SCHEMA.validateObject(parsedFile, options.filePath);\n } catch (e) {\n throw new Error(`The loc file is invalid. Error: ${e}`);\n }\n return parsedFile;\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import { ILocalizationFile, IParseFileOptions } from '../interfaces';
2
+ /**
3
+ * @public
4
+ */
5
+ export declare function parseResJson(options: IParseFileOptions): ILocalizationFile;
6
+ //# sourceMappingURL=parseResJson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseResJson.d.ts","sourceRoot":"","sources":["../../src/parsers/parseResJson.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAErE;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,CAiC1E"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3
+ // See LICENSE in the project root for license information.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.parseResJson = void 0;
6
+ const node_core_library_1 = require("@rushstack/node-core-library");
7
+ /**
8
+ * @public
9
+ */
10
+ function parseResJson(options) {
11
+ const resjsonFile = node_core_library_1.JsonFile.parseString(options.content);
12
+ const parsedFile = {};
13
+ const usedComments = new Map();
14
+ for (const [key, value] of Object.entries(resjsonFile)) {
15
+ if (key.startsWith('_') && key.endsWith('.comment')) {
16
+ if (!usedComments.has(key)) {
17
+ usedComments.set(key, false);
18
+ }
19
+ }
20
+ else {
21
+ const commentKey = `_${key}.comment`;
22
+ const comment = resjsonFile[commentKey];
23
+ usedComments.set(commentKey, true);
24
+ parsedFile[key] = { value, comment };
25
+ }
26
+ }
27
+ const orphanComments = [];
28
+ for (const [key, used] of usedComments) {
29
+ if (!used) {
30
+ orphanComments.push(key.slice(1, -'.comment'.length));
31
+ }
32
+ }
33
+ if (orphanComments.length > 0) {
34
+ throw new Error('The resjson file is invalid. Comments exist for the following string keys ' +
35
+ `that don't have values: ${orphanComments.join(', ')}.`);
36
+ }
37
+ return parsedFile;
38
+ }
39
+ exports.parseResJson = parseResJson;
40
+ //# sourceMappingURL=parseResJson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseResJson.js","sourceRoot":"","sources":["../../src/parsers/parseResJson.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAAwD;AAIxD;;GAEG;AACH,SAAgB,YAAY,CAAC,OAA0B;IACrD,MAAM,WAAW,GAA2B,4BAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,MAAM,UAAU,GAAsB,EAAE,CAAC;IAEzC,MAAM,YAAY,GAAyB,IAAI,GAAG,EAAE,CAAC;IACrD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;QACtD,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;YACnD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;gBAC1B,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;aAC9B;SACF;aAAM;YACL,MAAM,UAAU,GAAW,IAAI,GAAG,UAAU,CAAC;YAC7C,MAAM,OAAO,GAAuB,WAAW,CAAC,UAAU,CAAC,CAAC;YAC5D,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YACnC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;SACtC;KACF;IAED,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,YAAY,EAAE;QACtC,IAAI,CAAC,IAAI,EAAE;YACT,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;SACvD;KACF;IAED,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE;QAC7B,MAAM,IAAI,KAAK,CACb,4EAA4E;YAC1E,2BAA2B,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC1D,CAAC;KACH;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAjCD,oCAiCC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { JsonFile } from '@rushstack/node-core-library';\n\nimport { ILocalizationFile, IParseFileOptions } from '../interfaces';\n\n/**\n * @public\n */\nexport function parseResJson(options: IParseFileOptions): ILocalizationFile {\n const resjsonFile: Record<string, string> = JsonFile.parseString(options.content);\n const parsedFile: ILocalizationFile = {};\n\n const usedComments: Map<string, boolean> = new Map();\n for (const [key, value] of Object.entries(resjsonFile)) {\n if (key.startsWith('_') && key.endsWith('.comment')) {\n if (!usedComments.has(key)) {\n usedComments.set(key, false);\n }\n } else {\n const commentKey: string = `_${key}.comment`;\n const comment: string | undefined = resjsonFile[commentKey];\n usedComments.set(commentKey, true);\n parsedFile[key] = { value, comment };\n }\n }\n\n const orphanComments: string[] = [];\n for (const [key, used] of usedComments) {\n if (!used) {\n orphanComments.push(key.slice(1, -'.comment'.length));\n }\n }\n\n if (orphanComments.length > 0) {\n throw new Error(\n 'The resjson file is invalid. Comments exist for the following string keys ' +\n `that don't have values: ${orphanComments.join(', ')}.`\n );\n }\n\n return parsedFile;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rushstack/localization-utilities",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "This plugin contains some useful functions for localization.",
5
5
  "main": "lib/index.js",
6
6
  "typings": "dist/localization-utilities.d.ts",
@@ -12,21 +12,22 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@rushstack/node-core-library": "3.45.5",
15
- "@rushstack/typings-generator": "0.6.25",
16
- "decache": "~4.5.1",
15
+ "@rushstack/typings-generator": "0.6.26",
17
16
  "pseudolocale": "~1.1.0",
18
17
  "xmldoc": "~1.1.2"
19
18
  },
20
19
  "devDependencies": {
21
20
  "@rushstack/eslint-config": "2.6.0",
22
- "@rushstack/heft": "0.45.5",
23
- "@rushstack/heft-node-rig": "1.9.6",
21
+ "@rushstack/heft": "0.45.6",
22
+ "@rushstack/heft-node-rig": "1.9.7",
23
+ "@types/heft-jest": "1.0.1",
24
24
  "@types/node": "12.20.24",
25
25
  "@types/xmldoc": "1.1.4"
26
26
  },
27
27
  "scripts": {
28
28
  "build": "heft build --clean",
29
- "_phase:build": "heft build --clean"
29
+ "_phase:build": "heft build --clean",
30
+ "_phase:test": "heft test --no-build"
30
31
  },
31
32
  "readme": "# @rushstack/localization-utilities\n\nThis library provides a set of utilities for working with localization files.\n"
32
33
  }