modified: babel.config.js

modified:   example/App.tsx
	modified:   example/index.tsx
	modified:   index.ts
	modified:   package.json
	modified:   src/parser/Lexer.ts
	modified:   src/parser/mappingRule.ts
	modified:   src/parser/parseMappingRule.ts
	modified:   src/parser/parser.ts
	modified:   src/types/types.ts
	modified:   tsconfig.json
This commit is contained in:
wangyu 2023-12-06 15:37:37 +08:00
parent 925a6de0e2
commit fb3180f2f2
11 changed files with 97 additions and 90 deletions

View File

@ -13,7 +13,7 @@
* See the Mulan PSL v2 for more details.
*/
const {preset} = require("./jest.config");
const { preset } = require('./jest.config');
module.exports = {
presets: [
[
@ -23,19 +23,15 @@ module.exports = {
browsers: ['> 1%', 'last 2 versions', 'not ie <= 8'],
node: 'current',
},
useBuiltIns: 'usage',
corejs: 3,
},
],
['@babel/preset-typescript'],
[
'@babel/preset-typescript',
],
[
"@babel/preset-react",
'@babel/preset-react',
{
"runtime": "automatic",
"importSource": "openinula"
}
]
runtime: 'automatic',
importSource: 'openinula',
},
],
],
};

View File

@ -39,7 +39,7 @@ const App = () => {
<div className='container'>
<Example1/>
<Example2/>
<Example3/>
<Example3 locale={locale} setLocale={setLocale}/>
</div>
<div className='container'>
<Example4 locale={locale} messages={message}/>

View File

@ -17,9 +17,7 @@ import App from './App'
function render() {
Inula.render(
<>
<App/>
</>,
<App/>,
document.querySelector('#root') as any
)
}

View File

@ -54,7 +54,7 @@ export default {
IntlProvider: I18nProvider,
injectIntl: injectIntl,
RawIntlProvider: InjectProvider,
}
};
// 用于定义文本
export function defineMessages<K extends keyof any, T = MessageDescriptor, U = Record<K, T>>(msgs: U): U {

View File

@ -4,10 +4,11 @@
"description": "",
"main": "build/intl.umd.js",
"type": "commonjs",
"types": "build/index.d.ts",
"types": "build/@types/index.d.ts",
"scripts": {
"demo-serve": "webpack serve --mode=development",
"build": "rollup --config rollup.config.js",
"rollup-build": "rollup --config rollup.config.js && npm run build-types",
"build-types": "tsc -p tsconfig.json && rollup -c build-type.js",
"test": "jest --config jest.config.js",
"test-c": "jest --coverage"
},
@ -33,6 +34,7 @@
"@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-node-resolve": "^7.1.3",
"@rollup/plugin-typescript": "^11.0.0",
"rollup-plugin-dts": "^6.1.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@types/node": "^16.18.27",
@ -40,7 +42,6 @@
"babel": "^6.23.0",
"babel-jest": "^29.5.0",
"babel-loader": "^9.1.2",
"core-js": "3.31.0",
"html-webpack-plugin": "^5.5.1",
"jest": "29.3.1",
"jest-environment-jsdom": "^29.5.0",
@ -56,8 +57,6 @@
"typescript": "4.9.3",
"webpack": "^5.81.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.13.3",
"react": "18.2.0",
"react-dom": "18.2.0"
"webpack-dev-server": "^4.13.3"
}
}

View File

@ -14,51 +14,45 @@
*/
import ruleUtils from '../utils/parseRuleUtils';
import { LexerInterface } from "../types/interfaces";
const getMatch = ruleUtils.checkSticky()
? // 正则表达式具有 sticky 标志
(regexp, buffer) => regexp.exec(buffer)
: // 正则表达式具有 global 标志,匹配的字符串长度为 0则表示匹配失败
(regexp, buffer) => (regexp.exec(buffer)[0].length === 0 ? null : regexp.exec(buffer));
import { LexerInterface } from '../types/interfaces';
class Lexer<T> implements LexerInterface<T> {
readonly startState: string;
readonly states: Record<string, any>;
private buffer: string = '';
private stack: string[] = [];
private index;
private line;
private col;
private queuedText;
private state;
private groups;
private error;
private index: number = 0;
private line: number = 1;
private col: number = 1;
private queuedText: string = '';
private state: string = '';
private groups: string[] = [];
private error: Record<string, any> | undefined;
private regexp;
private fast;
private queuedGroup;
private value;
private fast: object = {};
private queuedGroup: string | null = '';
private value: string = '';
constructor(states, state) {
this.startState = state;
this.states = states;
constructor(unionReg: Record<string, any>, startState: string) {
this.startState = startState;
this.states = unionReg;
this.buffer = '';
this.stack = [];
this.reset();
}
public reset(data?, info?) {
public reset(data?: string) {
this.buffer = data || '';
this.index = 0;
this.line = info ? info.line : 1;
this.col = info ? info.col : 1;
this.queuedText = info ? info.queuedText : '';
this.setState(info ? info.state : this.startState);
this.stack = info && info.stack ? info.stack.slice() : [];
this.line = 1;
this.col = 1;
this.queuedText = '';
this.setState(this.startState);
this.stack = [];
return this;
}
private setState(state) {
private setState(state: string) {
if (!state || this.state === state) {
return;
}
@ -71,15 +65,15 @@ class Lexer<T> implements LexerInterface<T> {
}
private popState() {
this.setState(this.stack.pop());
this.setState(<string>this.stack.pop());
}
private pushState(state) {
private pushState(state: string) {
this.stack.push(this.state);
this.setState(state);
}
private getGroup(match) {
private getGroup(match: Record<string, any>) {
const groupCount = this.groups.length;
for (let i = 0; i < groupCount; i++) {
if (match[i + 1] !== undefined) {
@ -127,7 +121,7 @@ class Lexer<T> implements LexerInterface<T> {
const group = this.getGroup(match);
const text = match[0];
if (error.fallback && match.index !== index) {
if (error?.fallback && match.index !== index) {
this.queuedGroup = group;
this.queuedText = text;
return this.getToken(error, buffer.slice(index, match.index), index);
@ -136,7 +130,14 @@ class Lexer<T> implements LexerInterface<T> {
return this.getToken(group, text, index);
}
private getToken(group, text, offset) {
/**
* Token
* @param group
* @param text
* @param offset
* @private
*/
private getToken(group: any, text: string, offset: number) {
let lineNum = 0;
let last = 1; // 最后一个换行符的索引位置
if (group.lineBreaks) {
@ -192,9 +193,14 @@ class Lexer<T> implements LexerInterface<T> {
next: (): IteratorResult<T> => {
const token = this.next();
return { value: token, done: !token } as IteratorResult<T>;
}
}
},
};
}
}
const getMatch = ruleUtils.checkSticky()
? // 正则表达式具有 sticky 标志
(regexp, buffer) => regexp.exec(buffer)
: // 正则表达式具有 global 标志,匹配的字符串长度为 0则表示匹配失败
(regexp, buffer) => (regexp.exec(buffer)[0].length === 0 ? null : regexp.exec(buffer));
export default Lexer;

View File

@ -70,5 +70,5 @@ const select: Record<string, any> = {
export const mappingRule: Record<string, any> = {
body,
arg,
select
select,
};

View File

@ -16,16 +16,16 @@
import Lexer from './Lexer';
import { mappingRule } from './mappingRule';
import ruleUtils from '../utils/parseRuleUtils';
import { RawToken } from "../types/types";
import { RawToken } from '../types/types';
const defaultErrorRule = ruleUtils.getRuleOptions('error', { lineBreaks: true, shouldThrow: true });
// 解析规则并生成词法分析器所需的数据结构,以便进行词法分析操作
function parseRules(rules: Record<string, any>, hasStates: boolean): Record<string, any> {
let errorRule: Record<string, any> | null = null;
const fast = {};
let enableFast = true;
let unicodeFlag = null;
const fast: object = {};
let enableFast: boolean = true;
let unicodeFlag: boolean | null = null;
const groups: Record<string, any>[] = [];
const parts: string[] = [];
@ -108,11 +108,11 @@ export function checkStateGroup(group: Record<string, any>, name: string, map: R
}
// 将国际化解析规则注入分词器中
function parseMappingRule(mappingRule: Record<string, any>, start?: string): Lexer<RawToken> {
function parseMappingRule(mappingRule: Record<string, any>, startState?: string): Lexer<RawToken> {
const keys = Object.getOwnPropertyNames(mappingRule);
if (!start) {
start = keys[0];
if (!startState) {
startState = keys[0];
}
// 将每个状态的规则解析为规则数组,并存储在 ruleMap 对象中
@ -153,27 +153,27 @@ function parseMappingRule(mappingRule: Record<string, any>, start?: string): Lex
}
}
const map = {};
const mappingAllRules = {};
// 将规则映射为词法分析器数据结构,并存储在 map 对象中
// 将规则映射为词法分析器数据结构,并存储在 mappingAllRules 对象中
keys.forEach(key => {
map[key] = parseRules(ruleMap[key], true);
mappingAllRules[key] = parseRules(ruleMap[key], true);
});
// 检查状态组中的规则是否正确引用了其他状态
keys.forEach(name => {
const state = map[name];
const state = mappingAllRules[name];
const groups = state.groups;
groups.forEach(group => {
checkStateGroup(group, name, map);
checkStateGroup(group, name, mappingAllRules);
});
const fastKeys = Object.getOwnPropertyNames(state.fast);
fastKeys.forEach(fastKey => {
checkStateGroup(state.fast[fastKey], name, map);
checkStateGroup(state.fast[fastKey], name, mappingAllRules);
});
});
return new Lexer(map, start);
return new Lexer(mappingAllRules, startState);
}
function processFast(match, fast: {}, options) {

View File

@ -17,7 +17,7 @@ import { lexer } from './parseMappingRule';
import { RawToken, Token } from '../types/types';
import { DEFAULT_PLURAL_KEYS } from '../constants';
import { Content, FunctionArg, PlainArg, Select, TokenContext } from '../types/interfaces';
import Lexer from "./Lexer";
import Lexer from './Lexer';
const getContext = (lt: Record<string, any>): TokenContext => ({
offset: lt.offset,
@ -29,15 +29,14 @@ const getContext = (lt: Record<string, any>): TokenContext => ({
export const checkSelectType = (value: string): boolean => {
return value === 'plural' || value === 'select' || value === 'selectordinal';
}
};
class Parser {
lexer: Lexer<RawToken>;
cardinalKeys: string[] = DEFAULT_PLURAL_KEYS;
ordinalKeys: string[] = DEFAULT_PLURAL_KEYS;
constructor(message: string) {
this.lexer = lexer.reset(message);
lexer.reset(message);
}
isSelectKeyValid(token: RawToken, type: Select['type'], value: string) {
@ -60,7 +59,7 @@ class Parser {
isPlural = true;
}
for (const token of this.lexer) {
for (const token of lexer) {
switch (token.type) {
case 'offset': {
if (type === 'select') {
@ -97,7 +96,7 @@ class Parser {
parseToken(token: RawToken, isPlural: boolean): PlainArg | FunctionArg | Select {
const context = getContext(token);
const nextToken = this.lexer.next();
const nextToken = lexer.next();
if (!nextToken) {
throw new Error('The message end position is invalid.');
@ -111,7 +110,7 @@ class Parser {
return { type: 'argument', arg: token.value, ctx: context };
}
case 'func-simple': {
const end = this.lexer.next();
const end = lexer.next();
if (!end) {
throw new Error('The message end position is invalid.');
}
@ -159,7 +158,7 @@ class Parser {
const tokens: any[] = [];
let content: string | Content | null = null;
for (const token of this.lexer) {
for (const token of lexer) {
if (token.type === 'argument') {
if (content) {
content = null;
@ -175,7 +174,7 @@ class Parser {
} else if (token.type === 'doubleapos') {
tokens.push(token.value);
} else if (token.type === 'quoted') {
tokens.push(token.value)
tokens.push(token.value);
} else if (token.type === 'content') {
tokens.push(token.value);
} else {

View File

@ -21,9 +21,10 @@ import {
Select,
FunctionArg,
I18nContextProps,
configProps
configProps,
InjectedIntl,
} from './interfaces';
import I18n from "../core/I18n";
import I18n from '../core/I18n';
export type Error = string | ((message, id, context) => string);
@ -71,11 +72,15 @@ export type RawToken = {
col: number;
};
export type I18nProviderProps = I18nContextProps & configProps
export type I18nProviderProps = I18nContextProps & configProps;
export type IntlType = {
i18n: I18n;
formatMessage: Function,
formatNumber: Function,
formatDate: Function,
formatMessage: Function;
formatNumber: Function;
formatDate: Function;
};
export interface InjectedIntlProps {
intl: InjectedIntl;
}

View File

@ -31,6 +31,7 @@
"declaration": true,
"experimentalDecorators": true,
"downlevelIteration": true,
"declarationDir": "./build/@types",
// 使@types/node
"lib": [
"dom",
@ -53,19 +54,22 @@
}
},
"include": [
"./src/**/*",
"./src/format/**/*.ts",
"./example/**/*"
"./index.ts"
],
"exclude": [
"node_modules",
"lib",
"**/*.spec.ts",
"dev"
"dev",
"./example/**/*",
"./tsconfig.json"
],
"types": [
"node",
"jest",
"@testing-library/jest-dom"
],
"files": [
"./index.ts"
]
}