@rushstack/localization-utilities 0.2.1 → 0.5.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.
- package/dist/localization-utilities.d.ts +70 -4
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/{ResxReader.d.ts → LegacyResxReader.d.ts} +19 -2
- package/lib/LegacyResxReader.d.ts.map +1 -0
- package/lib/LegacyResxReader.js +43 -0
- package/lib/LegacyResxReader.js.map +1 -0
- package/lib/LocFileParser.d.ts +9 -8
- package/lib/LocFileParser.d.ts.map +1 -1
- package/lib/LocFileParser.js +43 -52
- package/lib/LocFileParser.js.map +1 -1
- package/lib/Pseudolocalization.d.ts.map +1 -1
- package/lib/Pseudolocalization.js +15 -5
- package/lib/Pseudolocalization.js.map +1 -1
- package/lib/{LocFileTypingsGenerator.d.ts → TypingsGenerator.d.ts} +4 -3
- package/lib/TypingsGenerator.d.ts.map +1 -0
- package/lib/{LocFileTypingsGenerator.js → TypingsGenerator.js} +19 -16
- package/lib/TypingsGenerator.js.map +1 -0
- package/lib/index.d.ts +7 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +12 -6
- package/lib/index.js.map +1 -1
- package/lib/interfaces.d.ts +16 -0
- package/lib/interfaces.d.ts.map +1 -1
- package/lib/interfaces.js.map +1 -1
- package/lib/parsers/parseLocJson.d.ts +6 -0
- package/lib/parsers/parseLocJson.d.ts.map +1 -0
- package/lib/parsers/parseLocJson.js +35 -0
- package/lib/parsers/parseLocJson.js.map +1 -0
- package/lib/parsers/parseResJson.d.ts +6 -0
- package/lib/parsers/parseResJson.d.ts.map +1 -0
- package/lib/parsers/parseResJson.js +42 -0
- package/lib/parsers/parseResJson.js.map +1 -0
- package/lib/parsers/parseResx.d.ts +20 -0
- package/lib/parsers/parseResx.d.ts.map +1 -0
- package/lib/{ResxReader.js → parsers/parseResx.js} +18 -23
- package/lib/parsers/parseResx.js.map +1 -0
- package/package.json +4 -3
- package/lib/LocFileTypingsGenerator.d.ts.map +0 -1
- package/lib/LocFileTypingsGenerator.js.map +0 -1
- package/lib/ResxReader.d.ts.map +0 -1
- package/lib/ResxReader.js.map +0 -1
|
@@ -9,6 +9,11 @@ import { StringValuesTypingsGenerator } from '@rushstack/typings-generator';
|
|
|
9
9
|
*/
|
|
10
10
|
export declare function getPseudolocalizer(options: IPseudolocaleOptions): (str: string) => string;
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export declare type IgnoreStringFunction = (filePath: string, stringName: string) => boolean;
|
|
16
|
+
|
|
12
17
|
/**
|
|
13
18
|
* @public
|
|
14
19
|
*/
|
|
@@ -27,10 +32,34 @@ export declare interface ILocalizedString {
|
|
|
27
32
|
/**
|
|
28
33
|
* @public
|
|
29
34
|
*/
|
|
30
|
-
export declare interface
|
|
31
|
-
terminal: ITerminal;
|
|
32
|
-
filePath: string;
|
|
35
|
+
export declare interface IParseFileOptions {
|
|
33
36
|
content: string;
|
|
37
|
+
filePath: string;
|
|
38
|
+
/**
|
|
39
|
+
* Optionally, provide a function that will be called for each string. If the function returns `true`
|
|
40
|
+
* the string will not be included.
|
|
41
|
+
*/
|
|
42
|
+
ignoreString?: IgnoreStringFunction;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
export declare interface IParseLocFileOptions extends IParseFileOptions, IParseResxOptionsBase {
|
|
49
|
+
parser?: ParserKind;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
export declare interface IParseResxOptions extends IParseFileOptions, IParseResxOptionsBase {
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
export declare interface IParseResxOptionsBase {
|
|
62
|
+
terminal: ITerminal;
|
|
34
63
|
resxNewlineNormalization: NewlineKind | undefined;
|
|
35
64
|
ignoreMissingResxComments: boolean | undefined;
|
|
36
65
|
}
|
|
@@ -54,6 +83,10 @@ export declare interface IPseudolocaleOptions {
|
|
|
54
83
|
}
|
|
55
84
|
|
|
56
85
|
/**
|
|
86
|
+
* @deprecated
|
|
87
|
+
*
|
|
88
|
+
* This has superseded by {@link IParseResxOptions}
|
|
89
|
+
*
|
|
57
90
|
* @public
|
|
58
91
|
*/
|
|
59
92
|
export declare interface IResxReaderOptions {
|
|
@@ -61,6 +94,11 @@ export declare interface IResxReaderOptions {
|
|
|
61
94
|
terminal: ITerminal;
|
|
62
95
|
newlineNormalization: NewlineKind | undefined;
|
|
63
96
|
warnOnMissingComment: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Optionally, provide a function that will be called for each string. If the function returns `true`
|
|
99
|
+
* the string will not be included.
|
|
100
|
+
*/
|
|
101
|
+
ignoreString?: IgnoreStringFunction;
|
|
64
102
|
}
|
|
65
103
|
|
|
66
104
|
/**
|
|
@@ -74,7 +112,7 @@ export declare interface ITypingsGeneratorOptions {
|
|
|
74
112
|
globsToIgnore?: string[];
|
|
75
113
|
resxNewlineNormalization?: NewlineKind | undefined;
|
|
76
114
|
ignoreMissingResxComments?: boolean | undefined;
|
|
77
|
-
ignoreString?:
|
|
115
|
+
ignoreString?: IgnoreStringFunction;
|
|
78
116
|
processComment?: (comment: string | undefined, resxFilePath: string, stringName: string) => string | undefined;
|
|
79
117
|
}
|
|
80
118
|
|
|
@@ -86,9 +124,37 @@ export declare function parseLocFile(options: IParseLocFileOptions): ILocalizati
|
|
|
86
124
|
/**
|
|
87
125
|
* @public
|
|
88
126
|
*/
|
|
127
|
+
export declare function parseLocJson({ content, filePath, ignoreString }: IParseFileOptions): ILocalizationFile;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @public
|
|
131
|
+
*/
|
|
132
|
+
export declare function parseResJson({ content, ignoreString, filePath }: IParseFileOptions): ILocalizationFile;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @public
|
|
136
|
+
*/
|
|
137
|
+
export declare function parseResx(options: IParseResxOptions): ILocalizationFile;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @public
|
|
141
|
+
*/
|
|
142
|
+
export declare type ParserKind = 'resx' | 'loc.json' | 'resjson';
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @deprecated
|
|
146
|
+
*
|
|
147
|
+
* Use {@link parseResx} instead.
|
|
148
|
+
*
|
|
149
|
+
* @public
|
|
150
|
+
*/
|
|
89
151
|
export declare function readResxAsLocFile(resxContents: string, options: IResxReaderOptions): ILocalizationFile;
|
|
90
152
|
|
|
91
153
|
/**
|
|
154
|
+
* @deprecated
|
|
155
|
+
*
|
|
156
|
+
* Use {@link parseResx} instead.
|
|
157
|
+
*
|
|
92
158
|
* @public
|
|
93
159
|
*/
|
|
94
160
|
export declare function readResxFileAsLocFile(options: IResxReaderOptions): ILocalizationFile;
|
package/dist/tsdoc-metadata.json
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { ITerminal, NewlineKind } from '@rushstack/node-core-library';
|
|
2
|
-
import { ILocalizationFile } from './interfaces';
|
|
2
|
+
import type { IgnoreStringFunction, ILocalizationFile } from './interfaces';
|
|
3
3
|
/**
|
|
4
|
+
* @deprecated
|
|
5
|
+
*
|
|
6
|
+
* This has superseded by {@link IParseResxOptions}
|
|
7
|
+
*
|
|
4
8
|
* @public
|
|
5
9
|
*/
|
|
6
10
|
export interface IResxReaderOptions {
|
|
@@ -8,13 +12,26 @@ export interface IResxReaderOptions {
|
|
|
8
12
|
terminal: ITerminal;
|
|
9
13
|
newlineNormalization: NewlineKind | undefined;
|
|
10
14
|
warnOnMissingComment: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Optionally, provide a function that will be called for each string. If the function returns `true`
|
|
17
|
+
* the string will not be included.
|
|
18
|
+
*/
|
|
19
|
+
ignoreString?: IgnoreStringFunction;
|
|
11
20
|
}
|
|
12
21
|
/**
|
|
22
|
+
* @deprecated
|
|
23
|
+
*
|
|
24
|
+
* Use {@link parseResx} instead.
|
|
25
|
+
*
|
|
13
26
|
* @public
|
|
14
27
|
*/
|
|
15
28
|
export declare function readResxFileAsLocFile(options: IResxReaderOptions): ILocalizationFile;
|
|
16
29
|
/**
|
|
30
|
+
* @deprecated
|
|
31
|
+
*
|
|
32
|
+
* Use {@link parseResx} instead.
|
|
33
|
+
*
|
|
17
34
|
* @public
|
|
18
35
|
*/
|
|
19
36
|
export declare function readResxAsLocFile(resxContents: string, options: IResxReaderOptions): ILocalizationFile;
|
|
20
|
-
//# sourceMappingURL=
|
|
37
|
+
//# sourceMappingURL=LegacyResxReader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LegacyResxReader.d.ts","sourceRoot":"","sources":["../src/LegacyResxReader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,SAAS,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAElF,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAG5E;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,oBAAoB,EAAE,WAAW,GAAG,SAAS,CAAC;IAC9C,oBAAoB,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CASpF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CAQtG"}
|
|
@@ -0,0 +1,43 @@
|
|
|
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.readResxAsLocFile = exports.readResxFileAsLocFile = void 0;
|
|
6
|
+
const node_core_library_1 = require("@rushstack/node-core-library");
|
|
7
|
+
const parseResx_1 = require("./parsers/parseResx");
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated
|
|
10
|
+
*
|
|
11
|
+
* Use {@link parseResx} instead.
|
|
12
|
+
*
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
function readResxFileAsLocFile(options) {
|
|
16
|
+
const content = node_core_library_1.FileSystem.readFile(options.resxFilePath);
|
|
17
|
+
return (0, parseResx_1.parseResx)({
|
|
18
|
+
...options,
|
|
19
|
+
content,
|
|
20
|
+
filePath: options.resxFilePath,
|
|
21
|
+
resxNewlineNormalization: options.newlineNormalization,
|
|
22
|
+
ignoreMissingResxComments: !options.warnOnMissingComment
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
exports.readResxFileAsLocFile = readResxFileAsLocFile;
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated
|
|
28
|
+
*
|
|
29
|
+
* Use {@link parseResx} instead.
|
|
30
|
+
*
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
function readResxAsLocFile(resxContents, options) {
|
|
34
|
+
return (0, parseResx_1.parseResx)({
|
|
35
|
+
...options,
|
|
36
|
+
content: resxContents,
|
|
37
|
+
filePath: options.resxFilePath,
|
|
38
|
+
resxNewlineNormalization: options.newlineNormalization,
|
|
39
|
+
ignoreMissingResxComments: !options.warnOnMissingComment
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
exports.readResxAsLocFile = readResxAsLocFile;
|
|
43
|
+
//# sourceMappingURL=LegacyResxReader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LegacyResxReader.js","sourceRoot":"","sources":["../src/LegacyResxReader.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAAkF;AAGlF,mDAAgD;AAqBhD;;;;;;GAMG;AACH,SAAgB,qBAAqB,CAAC,OAA2B;IAC/D,MAAM,OAAO,GAAW,8BAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAClE,OAAO,IAAA,qBAAS,EAAC;QACf,GAAG,OAAO;QACV,OAAO;QACP,QAAQ,EAAE,OAAO,CAAC,YAAY;QAC9B,wBAAwB,EAAE,OAAO,CAAC,oBAAoB;QACtD,yBAAyB,EAAE,CAAC,OAAO,CAAC,oBAAoB;KACzD,CAAC,CAAC;AACL,CAAC;AATD,sDASC;AAED;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,YAAoB,EAAE,OAA2B;IACjF,OAAO,IAAA,qBAAS,EAAC;QACf,GAAG,OAAO;QACV,OAAO,EAAE,YAAY;QACrB,QAAQ,EAAE,OAAO,CAAC,YAAY;QAC9B,wBAAwB,EAAE,OAAO,CAAC,oBAAoB;QACtD,yBAAyB,EAAE,CAAC,OAAO,CAAC,oBAAoB;KACzD,CAAC,CAAC;AACL,CAAC;AARD,8CAQC","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, NewlineKind } from '@rushstack/node-core-library';\n\nimport type { IgnoreStringFunction, ILocalizationFile } from './interfaces';\nimport { parseResx } from './parsers/parseResx';\n\n/**\n * @deprecated\n *\n * This has superseded by {@link IParseResxOptions}\n *\n * @public\n */\nexport interface IResxReaderOptions {\n resxFilePath: string;\n terminal: ITerminal;\n newlineNormalization: NewlineKind | undefined;\n warnOnMissingComment: boolean;\n /**\n * Optionally, provide a function that will be called for each string. If the function returns `true`\n * the string will not be included.\n */\n ignoreString?: IgnoreStringFunction;\n}\n\n/**\n * @deprecated\n *\n * Use {@link parseResx} instead.\n *\n * @public\n */\nexport function readResxFileAsLocFile(options: IResxReaderOptions): ILocalizationFile {\n const content: string = FileSystem.readFile(options.resxFilePath);\n return parseResx({\n ...options,\n content,\n filePath: options.resxFilePath,\n resxNewlineNormalization: options.newlineNormalization,\n ignoreMissingResxComments: !options.warnOnMissingComment\n });\n}\n\n/**\n * @deprecated\n *\n * Use {@link parseResx} instead.\n *\n * @public\n */\nexport function readResxAsLocFile(resxContents: string, options: IResxReaderOptions): ILocalizationFile {\n return parseResx({\n ...options,\n content: resxContents,\n filePath: options.resxFilePath,\n resxNewlineNormalization: options.newlineNormalization,\n ignoreMissingResxComments: !options.warnOnMissingComment\n });\n}\n"]}
|
package/lib/LocFileParser.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { ILocalizationFile, IParseFileOptions } from './interfaces';
|
|
2
|
+
import { IParseResxOptionsBase } from './parsers/parseResx';
|
|
3
3
|
/**
|
|
4
4
|
* @public
|
|
5
5
|
*/
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
export declare type ParserKind = 'resx' | 'loc.json' | 'resjson';
|
|
7
|
+
/**
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export interface IParseLocFileOptions extends IParseFileOptions, IParseResxOptionsBase {
|
|
11
|
+
parser?: ParserKind;
|
|
12
12
|
}
|
|
13
|
+
export declare function selectParserByFilePath(filePath: string): ParserKind;
|
|
13
14
|
/**
|
|
14
15
|
* @public
|
|
15
16
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocFileParser.d.ts","sourceRoot":"","sources":["../src/LocFileParser.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"LocFileParser.d.ts","sourceRoot":"","sources":["../src/LocFileParser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAwB,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAG/F,OAAO,EAAE,qBAAqB,EAAa,MAAM,qBAAqB,CAAC;AAEvE;;GAEG;AACH,oBAAY,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB,EAAE,qBAAqB;IACpF,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAUD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAUnE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,iBAAiB,CA2C7E"}
|
package/lib/LocFileParser.js
CHANGED
|
@@ -2,71 +2,62 @@
|
|
|
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
|
|
7
|
-
const
|
|
8
|
-
const
|
|
5
|
+
exports.parseLocFile = exports.selectParserByFilePath = void 0;
|
|
6
|
+
const parseLocJson_1 = require("./parsers/parseLocJson");
|
|
7
|
+
const parseResJson_1 = require("./parsers/parseResJson");
|
|
8
|
+
const parseResx_1 = require("./parsers/parseResx");
|
|
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
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
const { parser = selectParserByFilePath(options.filePath) } = options;
|
|
30
|
+
const fileCacheKey = `${options.filePath}?${parser}&${options.resxNewlineNormalization || 'none'}`;
|
|
31
|
+
const parseCacheEntry = parseCache.get(fileCacheKey);
|
|
32
|
+
if (parseCacheEntry) {
|
|
33
|
+
if (parseCacheEntry.content === options.content &&
|
|
34
|
+
parseCacheEntry.ignoreString === options.ignoreString) {
|
|
35
|
+
return parseCacheEntry.parsedFile;
|
|
19
36
|
}
|
|
20
37
|
}
|
|
21
38
|
let parsedFile;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
newlineNormalization: options.resxNewlineNormalization,
|
|
27
|
-
warnOnMissingComment: !options.ignoreMissingResxComments
|
|
28
|
-
});
|
|
29
|
-
}
|
|
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}`);
|
|
39
|
+
switch (parser) {
|
|
40
|
+
case 'resx': {
|
|
41
|
+
parsedFile = (0, parseResx_1.parseResx)(options);
|
|
42
|
+
break;
|
|
37
43
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
}
|
|
44
|
+
case 'loc.json': {
|
|
45
|
+
parsedFile = (0, parseLocJson_1.parseLocJson)(options);
|
|
46
|
+
break;
|
|
51
47
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
parsedFile[key].comment = comment;
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
orphanComments.push(key);
|
|
59
|
-
}
|
|
48
|
+
case 'resjson': {
|
|
49
|
+
parsedFile = (0, parseResJson_1.parseResJson)(options);
|
|
50
|
+
break;
|
|
60
51
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
`that don't have values: ${orphanComments.join(', ')}.`);
|
|
52
|
+
default: {
|
|
53
|
+
throw new Error(`Unsupported parser: ${parser}`);
|
|
64
54
|
}
|
|
65
55
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
parseCache.set(fileCacheKey, {
|
|
57
|
+
content: options.content,
|
|
58
|
+
parsedFile,
|
|
59
|
+
ignoreString: options.ignoreString
|
|
60
|
+
});
|
|
70
61
|
return parsedFile;
|
|
71
62
|
}
|
|
72
63
|
exports.parseLocFile = parseLocFile;
|
package/lib/LocFileParser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocFileParser.js","sourceRoot":"","sources":["../src/LocFileParser.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;
|
|
1
|
+
{"version":3,"file":"LocFileParser.js","sourceRoot":"","sources":["../src/LocFileParser.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAG3D,yDAAsD;AACtD,yDAAsD;AACtD,mDAAuE;AAoBvE,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,MAAM,YAAY,GAAW,GAAG,OAAO,CAAC,QAAQ,IAAI,MAAM,IAAI,OAAO,CAAC,wBAAwB,IAAI,MAAM,EAAE,CAAC;IAC3G,MAAM,eAAe,GAAiC,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACnF,IAAI,eAAe,EAAE;QACnB,IACE,eAAe,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO;YAC3C,eAAe,CAAC,YAAY,KAAK,OAAO,CAAC,YAAY,EACrD;YACA,OAAO,eAAe,CAAC,UAAU,CAAC;SACnC;KACF;IAED,IAAI,UAA6B,CAAC;IAClC,QAAQ,MAAM,EAAE;QACd,KAAK,MAAM,CAAC,CAAC;YACX,UAAU,GAAG,IAAA,qBAAS,EAAC,OAAO,CAAC,CAAC;YAChC,MAAM;SACP;QAED,KAAK,UAAU,CAAC,CAAC;YACf,UAAU,GAAG,IAAA,2BAAY,EAAC,OAAO,CAAC,CAAC;YACnC,MAAM;SACP;QAED,KAAK,SAAS,CAAC,CAAC;YACd,UAAU,GAAG,IAAA,2BAAY,EAAC,OAAO,CAAC,CAAC;YACnC,MAAM;SACP;QAED,OAAO,CAAC,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;SAClD;KACF;IAED,UAAU,CAAC,GAAG,CAAC,YAAY,EAAE;QAC3B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,UAAU;QACV,YAAY,EAAE,OAAO,CAAC,YAAY;KACnC,CAAC,CAAC;IAEH,OAAO,UAAU,CAAC;AACpB,CAAC;AA3CD,oCA2CC","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 type { IgnoreStringFunction, ILocalizationFile, IParseFileOptions } from './interfaces';\nimport { parseLocJson } from './parsers/parseLocJson';\nimport { parseResJson } from './parsers/parseResJson';\nimport { IParseResxOptionsBase, parseResx } from './parsers/parseResx';\n\n/**\n * @public\n */\nexport type ParserKind = 'resx' | 'loc.json' | 'resjson';\n\n/**\n * @public\n */\nexport interface IParseLocFileOptions extends IParseFileOptions, IParseResxOptionsBase {\n parser?: ParserKind;\n}\n\ninterface IParseCacheEntry {\n content: string;\n parsedFile: ILocalizationFile;\n ignoreString: IgnoreStringFunction | undefined;\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 const fileCacheKey: string = `${options.filePath}?${parser}&${options.resxNewlineNormalization || 'none'}`;\n const parseCacheEntry: IParseCacheEntry | undefined = parseCache.get(fileCacheKey);\n if (parseCacheEntry) {\n if (\n parseCacheEntry.content === options.content &&\n parseCacheEntry.ignoreString === options.ignoreString\n ) {\n return parseCacheEntry.parsedFile;\n }\n }\n\n let parsedFile: ILocalizationFile;\n switch (parser) {\n case 'resx': {\n parsedFile = parseResx(options);\n break;\n }\n\n case 'loc.json': {\n parsedFile = parseLocJson(options);\n break;\n }\n\n case 'resjson': {\n parsedFile = parseResJson(options);\n break;\n }\n\n default: {\n throw new Error(`Unsupported parser: ${parser}`);\n }\n }\n\n parseCache.set(fileCacheKey, {\n content: options.content,\n parsedFile,\n ignoreString: options.ignoreString\n });\n\n return parsedFile;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pseudolocalization.d.ts","sourceRoot":"","sources":["../src/Pseudolocalization.ts"],"names":[],"mappings":"
|
|
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
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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,
|
|
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"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { StringValuesTypingsGenerator } from '@rushstack/typings-generator';
|
|
2
2
|
import { ITerminal, NewlineKind } from '@rushstack/node-core-library';
|
|
3
|
+
import type { IgnoreStringFunction } from './interfaces';
|
|
3
4
|
/**
|
|
4
5
|
* @public
|
|
5
6
|
*/
|
|
@@ -11,7 +12,7 @@ export interface ITypingsGeneratorOptions {
|
|
|
11
12
|
globsToIgnore?: string[];
|
|
12
13
|
resxNewlineNormalization?: NewlineKind | undefined;
|
|
13
14
|
ignoreMissingResxComments?: boolean | undefined;
|
|
14
|
-
ignoreString?:
|
|
15
|
+
ignoreString?: IgnoreStringFunction;
|
|
15
16
|
processComment?: (comment: string | undefined, resxFilePath: string, stringName: string) => string | undefined;
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
@@ -19,7 +20,7 @@ export interface ITypingsGeneratorOptions {
|
|
|
19
20
|
*
|
|
20
21
|
* @public
|
|
21
22
|
*/
|
|
22
|
-
export declare class
|
|
23
|
+
export declare class TypingsGenerator extends StringValuesTypingsGenerator {
|
|
23
24
|
constructor(options: ITypingsGeneratorOptions);
|
|
24
25
|
}
|
|
25
|
-
//# sourceMappingURL=
|
|
26
|
+
//# sourceMappingURL=TypingsGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypingsGenerator.d.ts","sourceRoot":"","sources":["../src/TypingsGenerator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,4BAA4B,EAAsB,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEtE,OAAO,KAAK,EAAE,oBAAoB,EAAqB,MAAM,cAAc,CAAC;AAG5E;;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,oBAAoB,CAAC;IACpC,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,gBAAiB,SAAQ,4BAA4B;gBAC7C,OAAO,EAAE,wBAAwB;CAkCrD"}
|
|
@@ -2,7 +2,7 @@
|
|
|
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.
|
|
5
|
+
exports.TypingsGenerator = void 0;
|
|
6
6
|
const typings_generator_1 = require("@rushstack/typings-generator");
|
|
7
7
|
const LocFileParser_1 = require("./LocFileParser");
|
|
8
8
|
/**
|
|
@@ -10,34 +10,37 @@ const LocFileParser_1 = require("./LocFileParser");
|
|
|
10
10
|
*
|
|
11
11
|
* @public
|
|
12
12
|
*/
|
|
13
|
-
class
|
|
13
|
+
class TypingsGenerator extends typings_generator_1.StringValuesTypingsGenerator {
|
|
14
14
|
constructor(options) {
|
|
15
15
|
const { ignoreString, processComment } = options;
|
|
16
|
-
super(
|
|
16
|
+
super({
|
|
17
|
+
...options,
|
|
18
|
+
fileExtensions: ['.resx', '.resx.json', '.loc.json', '.resjson'],
|
|
19
|
+
parseAndGenerateTypings: (fileContents, filePath, resxFilePath) => {
|
|
17
20
|
const locFileData = (0, LocFileParser_1.parseLocFile)({
|
|
18
21
|
filePath: filePath,
|
|
19
22
|
content: fileContents,
|
|
20
23
|
terminal: this._options.terminal,
|
|
21
24
|
resxNewlineNormalization: options.resxNewlineNormalization,
|
|
22
|
-
ignoreMissingResxComments: options.ignoreMissingResxComments
|
|
25
|
+
ignoreMissingResxComments: options.ignoreMissingResxComments,
|
|
26
|
+
ignoreString
|
|
23
27
|
});
|
|
24
28
|
const typings = [];
|
|
25
29
|
// eslint-disable-next-line guard-for-in
|
|
26
30
|
for (const stringName in locFileData) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
comment = processComment(comment, resxFilePath, stringName);
|
|
31
|
-
}
|
|
32
|
-
typings.push({
|
|
33
|
-
exportName: stringName,
|
|
34
|
-
comment
|
|
35
|
-
});
|
|
31
|
+
let comment = locFileData[stringName].comment;
|
|
32
|
+
if (processComment) {
|
|
33
|
+
comment = processComment(comment, resxFilePath, stringName);
|
|
36
34
|
}
|
|
35
|
+
typings.push({
|
|
36
|
+
exportName: stringName,
|
|
37
|
+
comment
|
|
38
|
+
});
|
|
37
39
|
}
|
|
38
40
|
return { typings };
|
|
39
|
-
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
|
-
exports.
|
|
43
|
-
//# sourceMappingURL=
|
|
45
|
+
exports.TypingsGenerator = TypingsGenerator;
|
|
46
|
+
//# sourceMappingURL=TypingsGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypingsGenerator.js","sourceRoot":"","sources":["../src/TypingsGenerator.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAAgG;AAIhG,mDAA+C;AAqB/C;;;;GAIG;AACH,MAAa,gBAAiB,SAAQ,gDAA4B;IAChE,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;oBAC5D,YAAY;iBACb,CAAC,CAAC;gBAEH,MAAM,OAAO,GAAyB,EAAE,CAAC;gBAEzC,wCAAwC;gBACxC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;oBACpC,IAAI,OAAO,GAAuB,WAAW,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC;oBAClE,IAAI,cAAc,EAAE;wBAClB,OAAO,GAAG,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;qBAC7D;oBAED,OAAO,CAAC,IAAI,CAAC;wBACX,UAAU,EAAE,UAAU;wBACtB,OAAO;qBACR,CAAC,CAAC;iBACJ;gBAED,OAAO,EAAE,OAAO,EAAE,CAAC;YACrB,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF;AAnCD,4CAmCC","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 type { IgnoreStringFunction, 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?: IgnoreStringFunction;\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 TypingsGenerator 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 ignoreString\n });\n\n const typings: IStringValueTyping[] = [];\n\n // eslint-disable-next-line guard-for-in\n for (const stringName in locFileData) {\n let comment: string | undefined = locFileData[stringName].comment;\n if (processComment) {\n comment = processComment(comment, resxFilePath, stringName);\n }\n\n typings.push({\n exportName: stringName,\n comment\n });\n }\n\n return { typings };\n }\n });\n }\n}\n"]}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
export { ILocalizationFile, ILocalizedString, IPseudolocaleOptions } from './interfaces';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
1
|
+
export type { ILocalizationFile, ILocalizedString, IPseudolocaleOptions, IParseFileOptions, IgnoreStringFunction } from './interfaces';
|
|
2
|
+
export { parseLocJson } from './parsers/parseLocJson';
|
|
3
|
+
export { parseResJson } from './parsers/parseResJson';
|
|
4
|
+
export { parseResx, IParseResxOptions, IParseResxOptionsBase } from './parsers/parseResx';
|
|
5
|
+
export { parseLocFile, IParseLocFileOptions, ParserKind } from './LocFileParser';
|
|
6
|
+
export { ITypingsGeneratorOptions, TypingsGenerator } from './TypingsGenerator';
|
|
7
|
+
export { readResxFileAsLocFile, readResxAsLocFile, IResxReaderOptions } from './LegacyResxReader';
|
|
5
8
|
export { getPseudolocalizer } from './Pseudolocalization';
|
|
6
9
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC1F,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAClG,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -2,14 +2,20 @@
|
|
|
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.parseResx = 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; } });
|
|
10
|
+
var parseResx_1 = require("./parsers/parseResx");
|
|
11
|
+
Object.defineProperty(exports, "parseResx", { enumerable: true, get: function () { return parseResx_1.parseResx; } });
|
|
6
12
|
var LocFileParser_1 = require("./LocFileParser");
|
|
7
13
|
Object.defineProperty(exports, "parseLocFile", { enumerable: true, get: function () { return LocFileParser_1.parseLocFile; } });
|
|
8
|
-
var
|
|
9
|
-
Object.defineProperty(exports, "TypingsGenerator", { enumerable: true, get: function () { return
|
|
10
|
-
var
|
|
11
|
-
Object.defineProperty(exports, "readResxFileAsLocFile", { enumerable: true, get: function () { return
|
|
12
|
-
Object.defineProperty(exports, "readResxAsLocFile", { enumerable: true, get: function () { return
|
|
14
|
+
var TypingsGenerator_1 = require("./TypingsGenerator");
|
|
15
|
+
Object.defineProperty(exports, "TypingsGenerator", { enumerable: true, get: function () { return TypingsGenerator_1.TypingsGenerator; } });
|
|
16
|
+
var LegacyResxReader_1 = require("./LegacyResxReader");
|
|
17
|
+
Object.defineProperty(exports, "readResxFileAsLocFile", { enumerable: true, get: function () { return LegacyResxReader_1.readResxFileAsLocFile; } });
|
|
18
|
+
Object.defineProperty(exports, "readResxAsLocFile", { enumerable: true, get: function () { return LegacyResxReader_1.readResxAsLocFile; } });
|
|
13
19
|
var Pseudolocalization_1 = require("./Pseudolocalization");
|
|
14
20
|
Object.defineProperty(exports, "getPseudolocalizer", { enumerable: true, get: function () { return Pseudolocalization_1.getPseudolocalizer; } });
|
|
15
21
|
//# sourceMappingURL=index.js.map
|
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;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAS3D,uDAAsD;AAA7C,4GAAA,YAAY,OAAA;AACrB,uDAAsD;AAA7C,4GAAA,YAAY,OAAA;AACrB,iDAA0F;AAAjF,sGAAA,SAAS,OAAA;AAClB,iDAAiF;AAAxE,6GAAA,YAAY,OAAA;AACrB,uDAAgF;AAA7C,oHAAA,gBAAgB,OAAA;AACnD,uDAAkG;AAAzF,yHAAA,qBAAqB,OAAA;AAAE,qHAAA,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 IgnoreStringFunction\n} from './interfaces';\nexport { parseLocJson } from './parsers/parseLocJson';\nexport { parseResJson } from './parsers/parseResJson';\nexport { parseResx, IParseResxOptions, IParseResxOptionsBase } from './parsers/parseResx';\nexport { parseLocFile, IParseLocFileOptions, ParserKind } from './LocFileParser';\nexport { ITypingsGeneratorOptions, TypingsGenerator } from './TypingsGenerator';\nexport { readResxFileAsLocFile, readResxAsLocFile, IResxReaderOptions } from './LegacyResxReader';\nexport { getPseudolocalizer } from './Pseudolocalization';\n"]}
|
package/lib/interfaces.d.ts
CHANGED
|
@@ -28,4 +28,20 @@ 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
|
+
/**
|
|
38
|
+
* Optionally, provide a function that will be called for each string. If the function returns `true`
|
|
39
|
+
* the string will not be included.
|
|
40
|
+
*/
|
|
41
|
+
ignoreString?: IgnoreStringFunction;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
export declare type IgnoreStringFunction = (filePath: string, stringName: string) => boolean;
|
|
31
47
|
//# sourceMappingURL=interfaces.d.ts.map
|
package/lib/interfaces.d.ts.map
CHANGED
|
@@ -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;IACjB;;;OAGG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC;AAED;;GAEG;AACH,oBAAY,oBAAoB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC"}
|
package/lib/interfaces.js.map
CHANGED
|
@@ -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 * Optionally, provide a function that will be called for each string. If the function returns `true`\n * the string will not be included.\n */\n ignoreString?: IgnoreStringFunction;\n}\n\n/**\n * @public\n */\nexport type IgnoreStringFunction = (filePath: string, stringName: string) => boolean;\n"]}
|
|
@@ -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,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,iBAAiB,GAAG,iBAAiB,CAoBtG"}
|
|
@@ -0,0 +1,35 @@
|
|
|
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({ content, filePath, ignoreString }) {
|
|
14
|
+
const parsedFile = node_core_library_1.JsonFile.parseString(content);
|
|
15
|
+
try {
|
|
16
|
+
LOC_JSON_SCHEMA.validateObject(parsedFile, filePath);
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
throw new Error(`The loc file is invalid. Error: ${e}`);
|
|
20
|
+
}
|
|
21
|
+
if (ignoreString) {
|
|
22
|
+
const newParsedFile = {};
|
|
23
|
+
for (const [key, stringData] of Object.entries(parsedFile)) {
|
|
24
|
+
if (!ignoreString(filePath, key)) {
|
|
25
|
+
newParsedFile[key] = stringData;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return newParsedFile;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
return parsedFile;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.parseLocJson = parseLocJson;
|
|
35
|
+
//# 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,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAqB;IACjF,MAAM,UAAU,GAAsB,4BAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACpE,IAAI;QACF,eAAe,CAAC,cAAc,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;KACtD;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,EAAE,CAAC,CAAC;KACzD;IAED,IAAI,YAAY,EAAE;QAChB,MAAM,aAAa,GAAsB,EAAE,CAAC;QAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;YAC1D,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE;gBAChC,aAAa,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC;aACjC;SACF;QAED,OAAO,aAAa,CAAC;KACtB;SAAM;QACL,OAAO,UAAU,CAAC;KACnB;AACH,CAAC;AApBD,oCAoBC","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({ content, filePath, ignoreString }: IParseFileOptions): ILocalizationFile {\n const parsedFile: ILocalizationFile = JsonFile.parseString(content);\n try {\n LOC_JSON_SCHEMA.validateObject(parsedFile, filePath);\n } catch (e) {\n throw new Error(`The loc file is invalid. Error: ${e}`);\n }\n\n if (ignoreString) {\n const newParsedFile: ILocalizationFile = {};\n for (const [key, stringData] of Object.entries(parsedFile)) {\n if (!ignoreString(filePath, key)) {\n newParsedFile[key] = stringData;\n }\n }\n\n return newParsedFile;\n } else {\n return parsedFile;\n }\n}\n"]}
|
|
@@ -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,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,iBAAiB,GAAG,iBAAiB,CAoCtG"}
|
|
@@ -0,0 +1,42 @@
|
|
|
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({ content, ignoreString, filePath }) {
|
|
11
|
+
const resjsonFile = node_core_library_1.JsonFile.parseString(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
|
+
if (!(ignoreString === null || ignoreString === void 0 ? void 0 : ignoreString(filePath, key))) {
|
|
25
|
+
parsedFile[key] = { value, comment };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const orphanComments = [];
|
|
30
|
+
for (const [key, used] of usedComments) {
|
|
31
|
+
if (!used) {
|
|
32
|
+
orphanComments.push(key.slice(1, -'.comment'.length));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (orphanComments.length > 0) {
|
|
36
|
+
throw new Error('The resjson file is invalid. Comments exist for the following string keys ' +
|
|
37
|
+
`that don't have values: ${orphanComments.join(', ')}.`);
|
|
38
|
+
}
|
|
39
|
+
return parsedFile;
|
|
40
|
+
}
|
|
41
|
+
exports.parseResJson = parseResJson;
|
|
42
|
+
//# 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,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAqB;IACjF,MAAM,WAAW,GAA2B,4BAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC1E,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;YAEnC,IAAI,CAAC,CAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAG,QAAQ,EAAE,GAAG,CAAC,CAAA,EAAE;gBAClC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;aACtC;SACF;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;AApCD,oCAoCC","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({ content, ignoreString, filePath }: IParseFileOptions): ILocalizationFile {\n const resjsonFile: Record<string, string> = JsonFile.parseString(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\n if (!ignoreString?.(filePath, key)) {\n parsedFile[key] = { value, comment };\n }\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"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ITerminal, NewlineKind } from '@rushstack/node-core-library';
|
|
2
|
+
import type { ILocalizationFile, IParseFileOptions } from '../interfaces';
|
|
3
|
+
/**
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface IParseResxOptions extends IParseFileOptions, IParseResxOptionsBase {
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
export interface IParseResxOptionsBase {
|
|
12
|
+
terminal: ITerminal;
|
|
13
|
+
resxNewlineNormalization: NewlineKind | undefined;
|
|
14
|
+
ignoreMissingResxComments: boolean | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseResx(options: IParseResxOptions): ILocalizationFile;
|
|
20
|
+
//# sourceMappingURL=parseResx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseResx.d.ts","sourceRoot":"","sources":["../../src/parsers/parseResx.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAQ,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAG5E,OAAO,KAAK,EAAoB,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAI5F;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB,EAAE,qBAAqB;CAAG;AAEtF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,SAAS,CAAC;IACpB,wBAAwB,EAAE,WAAW,GAAG,SAAS,CAAC;IAClD,yBAAyB,EAAE,OAAO,GAAG,SAAS,CAAC;CAChD;AAaD;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,CAkBvE"}
|
|
@@ -2,22 +2,14 @@
|
|
|
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.
|
|
5
|
+
exports.parseResx = void 0;
|
|
6
6
|
const node_core_library_1 = require("@rushstack/node-core-library");
|
|
7
7
|
const xmldoc_1 = require("xmldoc");
|
|
8
8
|
const STRING_NAME_RESX = /^[A-z_$][A-z0-9_$]*$/;
|
|
9
9
|
/**
|
|
10
10
|
* @public
|
|
11
11
|
*/
|
|
12
|
-
function
|
|
13
|
-
const resxContents = node_core_library_1.FileSystem.readFile(options.resxFilePath);
|
|
14
|
-
return readResxAsLocFile(resxContents, options);
|
|
15
|
-
}
|
|
16
|
-
exports.readResxFileAsLocFile = readResxFileAsLocFile;
|
|
17
|
-
/**
|
|
18
|
-
* @public
|
|
19
|
-
*/
|
|
20
|
-
function readResxAsLocFile(resxContents, options) {
|
|
12
|
+
function parseResx(options) {
|
|
21
13
|
const writeError = options.terminal.writeErrorLine.bind(options.terminal);
|
|
22
14
|
const writeWarning = options.terminal.writeWarningLine.bind(options.terminal);
|
|
23
15
|
const loggingFunctions = {
|
|
@@ -30,12 +22,15 @@ function readResxAsLocFile(resxContents, options) {
|
|
|
30
22
|
_logWithLocation(writeWarning, message, filePath, line, position);
|
|
31
23
|
}
|
|
32
24
|
};
|
|
33
|
-
return _readResxAsLocFileInternal(
|
|
34
|
-
|
|
25
|
+
return _readResxAsLocFileInternal({
|
|
26
|
+
...options,
|
|
27
|
+
loggingFunctions
|
|
28
|
+
});
|
|
35
29
|
}
|
|
36
|
-
exports.
|
|
30
|
+
exports.parseResx = parseResx;
|
|
37
31
|
function _readResxAsLocFileInternal(options) {
|
|
38
|
-
const
|
|
32
|
+
const { ignoreString } = options;
|
|
33
|
+
const xmlDocument = new xmldoc_1.XmlDocument(options.content);
|
|
39
34
|
if (xmlDocument.name !== 'root') {
|
|
40
35
|
_logErrorWithLocation(options, `Expected RESX to have a "root" element, found "${xmlDocument.name}"`, xmlDocument);
|
|
41
36
|
}
|
|
@@ -57,7 +52,7 @@ function _readResxAsLocFileInternal(options) {
|
|
|
57
52
|
_logErrorWithLocation(options, `Duplicate string value "${stringName}"`, childNode);
|
|
58
53
|
}
|
|
59
54
|
const locString = _readDataElement(options, childNode);
|
|
60
|
-
if (locString) {
|
|
55
|
+
if (locString && !(ignoreString === null || ignoreString === void 0 ? void 0 : ignoreString(options.filePath, stringName))) {
|
|
61
56
|
locFile[stringName] = locString;
|
|
62
57
|
}
|
|
63
58
|
}
|
|
@@ -103,8 +98,8 @@ function _readDataElement(options, dataElement) {
|
|
|
103
98
|
else {
|
|
104
99
|
foundValueElement = true;
|
|
105
100
|
value = _readTextElement(options, childNode);
|
|
106
|
-
if (value && options.
|
|
107
|
-
value = node_core_library_1.Text.convertTo(value, options.
|
|
101
|
+
if (value && options.resxNewlineNormalization) {
|
|
102
|
+
value = node_core_library_1.Text.convertTo(value, options.resxNewlineNormalization);
|
|
108
103
|
}
|
|
109
104
|
}
|
|
110
105
|
break;
|
|
@@ -141,7 +136,7 @@ function _readDataElement(options, dataElement) {
|
|
|
141
136
|
_logErrorWithLocation(options, 'Missing string value in <data> element', dataElement);
|
|
142
137
|
}
|
|
143
138
|
else {
|
|
144
|
-
if (comment === undefined && options.
|
|
139
|
+
if (comment === undefined && options.ignoreMissingResxComments === false) {
|
|
145
140
|
_logWarningWithLocation(options, 'Missing string comment in <data> element', dataElement);
|
|
146
141
|
}
|
|
147
142
|
return {
|
|
@@ -177,18 +172,18 @@ function _readTextElement(options, element) {
|
|
|
177
172
|
}
|
|
178
173
|
function _logErrorWithLocation(options, message, element) {
|
|
179
174
|
if (element) {
|
|
180
|
-
options.loggingFunctions.logFileError(message, options.
|
|
175
|
+
options.loggingFunctions.logFileError(message, options.filePath, element.line + 1, element.column + 1);
|
|
181
176
|
}
|
|
182
177
|
else {
|
|
183
|
-
options.loggingFunctions.logFileError(message, options.
|
|
178
|
+
options.loggingFunctions.logFileError(message, options.filePath);
|
|
184
179
|
}
|
|
185
180
|
}
|
|
186
181
|
function _logWarningWithLocation(options, message, element) {
|
|
187
182
|
if (element) {
|
|
188
|
-
options.loggingFunctions.logFileWarning(message, options.
|
|
183
|
+
options.loggingFunctions.logFileWarning(message, options.filePath, element.line + 1, element.column + 1);
|
|
189
184
|
}
|
|
190
185
|
else {
|
|
191
|
-
options.loggingFunctions.logFileWarning(message, options.
|
|
186
|
+
options.loggingFunctions.logFileWarning(message, options.filePath);
|
|
192
187
|
}
|
|
193
188
|
}
|
|
194
189
|
function _logWithLocation(loggingFn, message, filePath, line, position) {
|
|
@@ -204,4 +199,4 @@ function _logWithLocation(loggingFn, message, filePath, line, position) {
|
|
|
204
199
|
}
|
|
205
200
|
loggingFn(`${location}: ${message}`);
|
|
206
201
|
}
|
|
207
|
-
//# sourceMappingURL=
|
|
202
|
+
//# sourceMappingURL=parseResx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseResx.js","sourceRoot":"","sources":["../../src/parsers/parseResx.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, Text, NewlineKind } from '@rushstack/node-core-library';\nimport { XmlDocument, XmlElement } from 'xmldoc';\n\nimport type { ILocalizedString, ILocalizationFile, IParseFileOptions } from '../interfaces';\n\nconst STRING_NAME_RESX: RegExp = /^[A-z_$][A-z0-9_$]*$/;\n\n/**\n * @public\n */\nexport interface IParseResxOptions extends IParseFileOptions, IParseResxOptionsBase {}\n\n/**\n * @public\n */\nexport interface IParseResxOptionsBase {\n terminal: ITerminal;\n resxNewlineNormalization: NewlineKind | undefined;\n ignoreMissingResxComments: boolean | undefined;\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<IParseResxOptions, 'terminal'> {\n loggingFunctions: ILoggingFunctions;\n}\n\n/**\n * @public\n */\nexport function parseResx(options: IParseResxOptions): 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 loggingFunctions\n });\n}\n\nfunction _readResxAsLocFileInternal(options: IResxReaderOptionsInternal): ILocalizationFile {\n const { ignoreString } = options;\n const xmlDocument: XmlDocument = new XmlDocument(options.content);\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 && !ignoreString?.(options.filePath, stringName)) {\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.resxNewlineNormalization) {\n value = Text.convertTo(value, options.resxNewlineNormalization);\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.ignoreMissingResxComments === false) {\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(message, options.filePath, element.line + 1, element.column + 1);\n } else {\n options.loggingFunctions.logFileError(message, options.filePath);\n }\n}\n\nfunction _logWarningWithLocation(\n options: IResxReaderOptionsInternal,\n message: string,\n element?: XmlElement | XmlDocument\n): void {\n if (element) {\n options.loggingFunctions.logFileWarning(message, options.filePath, element.line + 1, element.column + 1);\n } else {\n options.loggingFunctions.logFileWarning(message, options.filePath);\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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rushstack/localization-utilities",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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",
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@rushstack/node-core-library": "3.45.5",
|
|
15
15
|
"@rushstack/typings-generator": "0.6.26",
|
|
16
|
-
"decache": "~4.5.1",
|
|
17
16
|
"pseudolocale": "~1.1.0",
|
|
18
17
|
"xmldoc": "~1.1.2"
|
|
19
18
|
},
|
|
@@ -21,12 +20,14 @@
|
|
|
21
20
|
"@rushstack/eslint-config": "2.6.0",
|
|
22
21
|
"@rushstack/heft": "0.45.6",
|
|
23
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
|
}
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1 +0,0 @@
|
|
|
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,iCACA,OAAO,KACV,cAAc,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,CAAC,EAChE,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,IACD,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"]}
|
package/lib/ResxReader.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ResxReader.d.ts","sourceRoot":"","sources":["../src/ResxReader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,SAAS,EAAQ,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAGxF,OAAO,EAAoB,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAInE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,oBAAoB,EAAE,WAAW,GAAG,SAAS,CAAC;IAC9C,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAcD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CAGpF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CAmBtG"}
|
package/lib/ResxReader.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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"]}
|