Skip to content

Commit

Permalink
fix: lg resolver with locale (microsoft#2362)
Browse files Browse the repository at this point in the history
* fix lg resolver with locale

* generate importResolver in shared lib
  • Loading branch information
zhixzhan authored Mar 26, 2020
1 parent 4af5e5d commit dd373cf
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 84 deletions.
14 changes: 2 additions & 12 deletions Composer/packages/client/src/store/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import React, { useReducer, useRef } from 'react';
import once from 'lodash/once';
import { ImportResolverDelegate, LGParser } from 'botbuilder-lg';
import { LgFile, LuFile } from '@bfc/indexers';
import { importResolverGenerator } from '@bfc/shared';

import { prepareAxios } from '../utils/auth';
import { getFileName, getBaseName, getExtension } from '../utils/fileUtil';

import { reducer } from './reducer';
import bindActions from './action/bindActions';
Expand Down Expand Up @@ -121,17 +121,7 @@ export const StoreProvider: React.FC<StoreProviderProps> = props => {
actions: boundActions,
dispatch: interceptDispatch,
resolvers: {
lgImportresolver: function(source: string, id: string) {
const locale = getExtension(source);
const targetFileName = getFileName(id);
let targetFileId = getBaseName(targetFileName);
if (locale) {
targetFileId += `.${locale}`;
}
const targetFile = getState().lgFiles.find(({ id }) => id === targetFileId);
if (!targetFile) throw new Error(`${id} lg file not found`);
return { id, content: targetFile.content };
} as ImportResolverDelegate,
lgImportresolver: importResolverGenerator(getState().lgFiles, '.lg'),
lgFileResolver: function(id: string) {
const state = getState();
const { locale, lgFiles } = state;
Expand Down
18 changes: 3 additions & 15 deletions Composer/packages/client/src/store/reducer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
import get from 'lodash/get';
import set from 'lodash/set';
import formatMessage from 'format-message';
import { SensitiveProperties } from '@bfc/shared';
import { SensitiveProperties, importResolverGenerator } from '@bfc/shared';
import { lgIndexer, luIndexer, LuFile, DialogInfo, dialogIndexer } from '@bfc/indexers';
import { ImportResolverDelegate } from 'botbuilder-lg';

import { ActionTypes, FileTypes, BotStatus } from '../../constants';
import { DialogSetting, ReducerFunc } from '../types';
import { UserTokenPayload } from '../action/types';
import { getExtension, getFileName, getBaseName } from '../../utils';
import { getExtension } from '../../utils';
import settingStorage from '../../utils/dialogSettingStorage';
import luFileStatusStorage from '../../utils/luFileStatusStorage';
import { getReferredFiles } from '../../utils/luUtil';
Expand Down Expand Up @@ -146,18 +145,7 @@ const updateLgTemplate: ReducerFunc = (state, { id, content }) => {
}
return lgFile;
});
const lgImportresolver: ImportResolverDelegate = function(source: string, id: string) {
const locale = getExtension(source);
const targetFileName = getFileName(id);
let targetFileId = getBaseName(targetFileName);
if (locale) {
targetFileId += `.${locale}`;
}
const targetFile = lgFiles.find(({ id }) => id === targetFileId);
if (!targetFile) throw new Error(`file not found`);
return { id, content: targetFile.content };
};

const lgImportresolver = importResolverGenerator(lgFiles, '.lg');
state.lgFiles = lgFiles.map(lgFile => {
const { parse } = lgIndexer;
const { id, content } = lgFile;
Expand Down
1 change: 1 addition & 0 deletions Composer/packages/lib/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export * from './constant';
export * from './lgUtils';
export * from './walkerUtils';
export * from './copyUtils';
export * from './resolverFactory';
51 changes: 51 additions & 0 deletions Composer/packages/lib/shared/src/resolverFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

export declare type ResolverResource = { content: string; id: string };
export declare type ImportResolverDelegate = (source: string, resourceId: string) => ResolverResource;

function getFileName(path: string): string {
return path.split('/').pop() || path;
}

/**
*
* @param resources resources feed to resolver
* @param ext resource extension, e.g. .lg, .lu
* @param defaultLocale complete resource id = [id].[locale][ext]
*/
export function importResolverGenerator(
resources: ResolverResource[],
ext = '',
defaultLocale = 'en-us'
): ImportResolverDelegate {
/**
* @param source current file id
* @param resourceId imported file id
* for example:
* in todosample.en-us.lg:
* [import](../common/common.lg)
*
* would resolve to common.en-us.lg || common.lg
*
* source = todosample || todosample.en-us || todosample.en-us.lg || todosample.lg
* resourceId = common || common.lg || ../common/common.lg
*
*/
return (source: string, resourceId: string) => {
// eslint-disable-next-line security/detect-non-literal-regexp
const extReg = new RegExp(ext + '$');
const sourceId = getFileName(source).replace(extReg, '');
const locale = sourceId.split('.').length > 1 ? sourceId.split('.').pop() : defaultLocale;
const targetId = getFileName(resourceId).replace(extReg, '');

const targetFile =
resources.find(({ id }) => id === `${targetId}.${locale}`) || resources.find(({ id }) => id === targetId);

if (!targetFile) throw new Error(`file not found`);
return {
id: resourceId,
content: targetFile.content,
};
};
}
43 changes: 15 additions & 28 deletions Composer/packages/server/src/models/bot/botProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import fs from 'fs';

import has from 'lodash/has';
import { getNewDesigner } from '@bfc/shared';
import { getNewDesigner, importResolverGenerator } from '@bfc/shared';
import {
FileInfo,
DialogInfo,
Expand Down Expand Up @@ -110,7 +110,7 @@ export class BotProject {
this.files = await this._getFiles();
this.settings = await this.getEnvSettings('', false);
this.dialogs = this.indexDialogs();
this.lgFiles = lgIndexer.index(this.files, this._lgImportResolver);
this.lgFiles = lgIndexer.index(this.files, this._getLgImportResolver());
this.luFiles = luIndexer.index(this.files);
await this._checkProjectStructure();
if (this.settings) {
Expand All @@ -119,7 +119,7 @@ export class BotProject {
};

public getIndexes = () => {
this.lgFiles = lgIndexer.index(this.files, this._lgImportResolver);
this.lgFiles = lgIndexer.index(this.files, this._getLgImportResolver());
return {
botName: this.name,
location: this.dir,
Expand Down Expand Up @@ -545,30 +545,17 @@ export class BotProject {
return dialogIndexer.index(this.files, this.name, this.getSchemas().sdk.content);
}

/**
* @param source current file id
* @param id imported file path
* for example:
* in todosample.en-us.lg:
* [import](../common/common.lg)
*
* resolve to common.en-us.lg
*
* source = todosample.en-us || AddToDo
* id = ../common/common.lg || common.lg || common
*/
private _lgImportResolver = (source: string, id: string) => {
const locale = source.split('.').length > 1 ? source.split('.').pop() : '';
let targetId = Path.basename(id, '.lg');
if (locale) {
targetId += `.${locale}`;
}
const targetFile = this.lgFiles.find(({ id }) => id === targetId);
if (!targetFile) throw new Error('file not found');
return {
id,
content: targetFile.content,
};
private _getLgImportResolver = () => {
const lgFiles = this.files
.filter(({ name }) => name.endsWith('.lg'))
.map(({ name, content }) => {
return {
id: Path.basename(name, '.lg'),
content,
};
});

return importResolverGenerator(lgFiles, '.lg', this.locale);
};

// re index according to file change in a certain path
Expand All @@ -580,7 +567,7 @@ export class BotProject {
this.dialogs = this.indexDialogs();
break;
case '.lg':
this.lgFiles = lgIndexer.index(this.files, this._lgImportResolver);
this.lgFiles = lgIndexer.index(this.files, this._getLgImportResolver());
break;
case '.lu':
this.luFiles = luIndexer.index(this.files);
Expand Down
42 changes: 13 additions & 29 deletions Composer/packages/server/src/services/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import merge from 'lodash/merge';
import find from 'lodash/find';
import { TextFile } from '@bfc/indexers';
import { importResolverGenerator, ResolverResource } from '@bfc/shared';

import { BotProject } from '../models/bot/botProject';
import { LocationRef } from '../models/bot/interface';
Expand Down Expand Up @@ -33,38 +33,22 @@ export class BotProjectService {
}
}

public static lgImportResolver(source: string, id: string, projectId: string): TextFile {
public static lgImportResolver(source: string, id: string, projectId: string): ResolverResource {
BotProjectService.initialize();
let targetId = Path.basename(id, '.lg');
if (targetId.lastIndexOf('.') === -1) {
const locale = source.lastIndexOf('.') > 0 ? source.split('.').pop() : 'en-us';
targetId += `.${locale}`;
}
const targetFile = BotProjectService.currentBotProjects
.find(({ id }) => id === projectId)
?.lgFiles.find(({ id }) => id === targetId);
if (!targetFile) throw new Error('lg file not found');
return {
id,
content: targetFile.content,
};
const project = BotProjectService.currentBotProjects.find(({ id }) => id === projectId);
if (!project) throw new Error('project not found');

const resolver = importResolverGenerator(project.lgFiles, '.lg');
return resolver(source, id);
}

public static luImportResolver(source: string, id: string, projectId: string): any {
public static luImportResolver(source: string, id: string, projectId: string): ResolverResource {
BotProjectService.initialize();
let targetId = Path.basename(id, '.lu');
if (targetId.lastIndexOf('.') === -1) {
const locale = source.lastIndexOf('.') > 0 ? source.split('.').pop() : 'en-us';
targetId += `.${locale}`;
}
const targetFile = BotProjectService.currentBotProjects
.find(({ id }) => id === projectId)
?.luFiles.find(({ id }) => id === targetId);
if (!targetFile) throw new Error('lu file not found');
return {
id,
content: targetFile.content,
};
const project = BotProjectService.currentBotProjects.find(({ id }) => id === projectId);
if (!project) throw new Error('project not found');

const resolver = importResolverGenerator(project.luFiles, '.lu');
return resolver(source, id);
}

public static staticMemoryResolver(projectId: string): string[] {
Expand Down

0 comments on commit dd373cf

Please sign in to comment.