Skip to content

Commit

Permalink
✨ add elem if already generate to file
Browse files Browse the repository at this point in the history
  • Loading branch information
ChenCMD committed Nov 24, 2020
1 parent 83bf685 commit 3ab0ebe
Show file tree
Hide file tree
Showing 14 changed files with 143 additions and 42 deletions.
37 changes: 36 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,41 @@
"type": "string",
"markdownDescription": "%mcdutil.config.createDatapackTemplate.customTemplate.generates.content%"
}
},
"append": {
"type": "object",
"markdownDescription": "%mcdutil.config.createDatapackTemplate.customTemplate.generates.append%",
"required": [
"key",
"elem"
],
"properties": {
"key": {
"type": "string"
},
"elem": {
"oneOf": [
{
"type": "array"
},
{
"type": "boolean"
},
{
"type": "integer"
},
{
"type": "number"
},
{
"type": "object"
},
{
"type": "string"
}
]
}
}
}
}
}
Expand Down Expand Up @@ -540,4 +575,4 @@
"webpack": "^5.3.2",
"webpack-cli": "^4.1.0"
}
}
}
1 change: 1 addition & 0 deletions package.nls.ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"mcdutil.config.createDatapackTemplate.customTemplate.description": "説明文",
"mcdutil.config.createDatapackTemplate.customTemplate.detail": "詳細な説明",
"mcdutil.config.createDatapackTemplate.customTemplate.generates": "選択時に生成されるファイル/フォルダ",
"mcdutil.config.createDatapackTemplate.customTemplate.generates.append": "対象がjsonで既に生成されている場合にkeyにelemを追加します。",
"mcdutil.config.createDatapackTemplate.customTemplate.generates.type": "ファイルかフォルダか",
"mcdutil.config.createDatapackTemplate.customTemplate.generates.rel": "DatapackName以下の相対ファイルパス (ファイルの場合拡張子まで記載が必要です)",
"mcdutil.config.createDatapackTemplate.customTemplate.generates.rel.error": "\\\\ : * ? \" < > | はファイル/フォルダ名に使えません",
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"mcdutil.config.createDatapackTemplate.customTemplate.description": "Explanatory text",
"mcdutil.config.createDatapackTemplate.customTemplate.detail": "Detailed explanation",
"mcdutil.config.createDatapackTemplate.customTemplate.generates": "Files/folders generated when selected",
"mcdutil.config.createDatapackTemplate.customTemplate.generates.append": "Add elem to key if the target has already been generated in json.",
"mcdutil.config.createDatapackTemplate.customTemplate.generates.type": "file or folder",
"mcdutil.config.createDatapackTemplate.customTemplate.generates.rel": "Relative file path under DatapackName (In case of file, extension is required)",
"mcdutil.config.createDatapackTemplate.customTemplate.generates.rel.error": "\\\\ : * ? \" < > | cannot be used for file/folder names",
Expand Down
73 changes: 47 additions & 26 deletions src/commands/createDatapackTemplate/main.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { getDate, getResourcePath } from '../../utils/common';
import { createProgressBar, showError, showInfo } from '../../utils/vscodeWrapper';
import { getDate, getResourcePath, appendElemFromKey } from '../../utils/common';
import { createProgressBar, getIndent, showError, showInfo } from '../../utils/vscodeWrapper';
import path from 'path';
import { TextEncoder } from 'util';
import '../../utils/methodExtensions';
import { packMcMetaData } from './utils/data';
import * as file from '../../utils/file';
import { locale } from '../../locales';
import { resolveVars, ContextContainer } from '../../types/ContextContainer';
import { getFileType } from '../../types/FileTypes';
import { codeConsole, config, versionInformation } from '../../extension';
import rfdc from 'rfdc';
import { GenerateFileData, GetGitHubDataFunc, QuickPickFiles } from './types/QuickPickFiles';
import { getVanillaData } from '../../utils/vanillaData';
import { listenDatapackName, listenDescription, listenNamespace, listenGenerateTemplate, listenGenerateDir, listenGenerateType } from './utils/userInputs';
import { UserCancelledError } from '../../types/Error';
import { GenerateError, UserCancelledError } from '../../types/Error';

export async function createDatapack(): Promise<void>;
export async function createDatapack(genType: string, dir: string): Promise<void>;
Expand All @@ -34,7 +33,7 @@ export async function createDatapack(genType?: string, dir?: string): Promise<vo
// 生成するファイル/フォルダを選択
const createItems = await listenGenerateTemplate(ctx);
// 選択されたデータを生成用の形式に加工
const generateData = await toGenerateData(createItems);
const generateData = await toGenerateData(createItems, genType);
// 生成
await generate(ctx, generateData);
} catch (error) {
Expand All @@ -48,55 +47,77 @@ export async function createDatapack(genType?: string, dir?: string): Promise<vo
export async function generate(ctxContainer: ContextContainer, generateData: GenerateFileData[]): Promise<void> {
await createProgressBar(locale('create-datapack-template.progress.title'), async report => {
const message = locale('create-datapack-template.progress.creating');
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const datapackRoot = ctxContainer.datapackRoot!;
report({ increment: 0, message });
report({ message });

for (const item of generateData) {
const filePath = path.join(datapackRoot, resolveVars(item.rel, ctxContainer));

if (item.type === 'folder') {
await file.createDir(filePath);
} else if (!await file.pathAccessible(filePath)) {
const fileResourcePath = getResourcePath(filePath, datapackRoot, getFileType(filePath, datapackRoot));
const str = item.content?.map(v => resolveVars(v, { fileResourcePath, ...ctxContainer })).join('\r\n');
await file.createFile(filePath, new TextEncoder().encode(str ?? ''));
try {
await singleGenerate(ctxContainer, item);
} catch (error) {
if (error instanceof Error) showError(error.message);
else showError(error.toString());
codeConsole.appendLine(error.stack ?? error.toString());
} finally {
report({ increment: 100 / generateData.length, message });
}
report({ increment: 100 / generateData.length, message });
}
showInfo(locale('create-datapack-template.complete'));
});
}

export async function toGenerateData(createItems: QuickPickFiles[]): Promise<GenerateFileData[]> {
const generateData = createItems.flat(v => v.generates);
export async function singleGenerate(ctxContainer: ContextContainer, item: GenerateFileData): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const datapackRoot = ctxContainer.datapackRoot!;
const filePath = path.join(datapackRoot, resolveVars(item.rel, ctxContainer));

if (item.type === 'folder') {
await file.createDir(filePath);
return;
}
if (item.type === 'file') {
if (!await file.pathAccessible(filePath)) {
const contents = item.content?.map(v => resolveVars(v, { fileResourcePath: getResourcePath(filePath, datapackRoot), ...ctxContainer }));
await file.createFile(filePath, new TextEncoder().encode(contents?.join('\r\n') ?? ''));
} else if (item.jsonAppend) {
// eslint-disable-next-line prefer-const
let { key, elem } = item.jsonAppend;
const parsedJson = JSON.parse(await file.readFile(filePath));
if (typeof elem === 'string') elem = resolveVars(elem, ctxContainer);
if (!appendElemFromKey(parsedJson, key, elem)) throw new GenerateError(locale('could-not-access-key', filePath, key));
file.writeFile(filePath, JSON.stringify(parsedJson, undefined, ' '.repeat(getIndent(filePath))));
}
}
}

export async function toGenerateData(createItems: QuickPickFiles[], genType: string): Promise<GenerateFileData[]> {
const ans = createItems.flat(v => v.generates);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const funcs = createItems.filter(v => v.func !== undefined).flat(v => v.func!);

generateData.push(rfdc()(packMcMetaData));
if (genType === 'create-datapack-template.create') ans.push(rfdc()(packMcMetaData));

for (const item of funcs.map((func, index) => ({ func, index }))) {
await createProgressBar(
locale('create-datapack-template.progress.title'),
async report => generateData.push(...await download(item.func, item.index, funcs.length, report))
async report => ans.push(...await download(item.func, item.index, funcs.length, report))
);
}

return generateData;
return ans;
}

export async function download(
func: GetGitHubDataFunc, index: number, itemLength: number, report: (value: { increment: number, message: string }) => void
func: GetGitHubDataFunc, index: number, itemLength: number, report: (value: { increment?: number, message: string }) => void
): Promise<GenerateFileData[]> {
const message = locale('create-datapack-template.progress.download', index + 1, itemLength);
report({ increment: 0, message });
report({ message });

const fileDatas = await getVanillaData(
const ans = await getVanillaData(
config.createDatapackTemplate.dataVersion,
versionInformation,
func,
func.rel,
(_, m) => report({ increment: 100 / m, message })
);

return fileDatas.map(fileData => ({ type: 'file', ...fileData }));
return ans.map(fileData => ({ type: 'file', ...fileData }));
}
12 changes: 10 additions & 2 deletions src/commands/createDatapackTemplate/utils/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ export const pickItems: QuickPickFiles[] = [
' "%namespace%:load"',
' ]',
'}'
]
],
jsonAppend: {
key: 'values',
elem: '%namespace%:load'
}
},
{
type: 'file',
Expand All @@ -50,7 +54,11 @@ export const pickItems: QuickPickFiles[] = [
' "%namespace%:tick"',
' ]',
'}'
]
],
jsonAppend: {
key: 'value',
elem: '%namespace%:tick'
}
},
{
type: 'file',
Expand Down
6 changes: 2 additions & 4 deletions src/commands/createDatapackTemplate/utils/userInputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ export async function listenGenerateType(): Promise<string> {

export async function listenGenerateDir(ctxContainer: ContextContainer, genType: string): Promise<void> {
let title: string;
if (genType === 'create-datapack-template.create')
title = locale('create-datapack-template.dialog-title-directory');
else
title = locale('create-datapack-template.dialog-title-datapack');
if (genType === 'create-datapack-template.create') title = locale('create-datapack-template.dialog-title-directory');
else title = locale('create-datapack-template.dialog-title-datapack');
const dir = await listenOpenDir(title, locale('create-datapack-template.dialog-label')).then(v => v.fsPath);

if (genType === 'create-datapack-template.create') {
Expand Down
6 changes: 3 additions & 3 deletions src/commands/createFile/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ export async function createFile(uri: Uri): Promise<void> {

try {
const openFilePath = getTextEditor().document.uri.fsPath;
const nowOpenFileType = getFileType(path.dirname(openFilePath), datapackRoot) ?? '';
ctxContainer.nowOpenFileType = nowOpenFileType;
ctxContainer.nowOpenFileResourcePath = nowOpenFileType !== '' ? getResourcePath(openFilePath, datapackRoot, nowOpenFileType as FileType) : '';
const nowOpenFileType = getFileType(path.dirname(openFilePath), datapackRoot);
ctxContainer.nowOpenFileType = nowOpenFileType ?? '';
ctxContainer.nowOpenFileResourcePath = getResourcePath(openFilePath, datapackRoot, nowOpenFileType) ?? '';
ctxContainer.nowOpenFileName = openFilePath.match(/([^/\\]*(?=\.(?!.*\.))|(?<=^|(?:\/|\\))[^./\\]*$)/)?.shift() ?? '';
ctxContainer.nowOpenFileExtname = openFilePath.match(/(?<=\.)[^./\\]*?$/)?.shift() ?? '';
} catch (error) {
Expand Down
1 change: 1 addition & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"copy-resource-path.not-datapack": "The resource path cannot be obtained because it is not in the datapack.",
"copy-resource-path.unknown-filetype": "Unable to get the resource path for this file.",
"could-not-access-key": "Could not access key: \"%1%\" of file: \"%0%\".",
"create-file.not-datapack": "Cannot create file because it is not in a datapack.",
"create-file.unknown-filetype": "You can't create a file here.",
"create-file.unknown-filetype.listen-add": "You can't create a file here.\nWould you like to add a template to your datapack \"%0%\"?",
Expand Down
1 change: 1 addition & 0 deletions src/locales/ja.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"copy-resource-path.not-datapack": "datapack内では無いためリソースパスを取得できません。",
"copy-resource-path.unknown-filetype": "このファイルのリソースパスを取得できません。",
"could-not-access-key": "ファイル: \"%0%\"のkey: \"%1%\"にアクセス出来ませんでした。",
"create-file.not-datapack": "datapack内ではないためファイルを作成できません。",
"create-file.unknown-filetype": "ここにファイルを作成することはできません。",
"create-file.unknown-filetype.listen-add": "ここにファイルを作成することはできません。\ndatapack \"%0%\"にテンプレートを追加しますか?",
Expand Down
9 changes: 8 additions & 1 deletion src/types/FileData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export interface FileData {
rel: string
content?: string[]
content?: string[],
jsonAppend?: AppendElement
}

export interface AppendElement {
key: string
// eslint-disable-next-line @typescript-eslint/no-explicit-any
elem: any
}
5 changes: 5 additions & 0 deletions src/types/FileTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,8 @@ export function getFileType(filePath: string, datapackRoot: string): FileType |
}
return undefined;
}

export function getFilePath(fileType: FileType | undefined): string | undefined {
if (!fileType) return undefined;
return fileTypeFolderName[fileType];
}
22 changes: 19 additions & 3 deletions src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as path from 'path';
import * as file from './file';
import { locale } from '../locales';
import dateFormat from 'dateformat';
import { FileType, fileTypeFolderName } from '../types/FileTypes';
import { FileType, getFilePath, getFileType } from '../types/FileTypes';
import { DownloadTimeOutError } from '../types/Error';

export async function setTimeOut<T>(milisec: number): Promise<T> {
Expand All @@ -13,13 +13,29 @@ export function getDate(format: string): string {
return dateFormat(Date.now(), format);
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
export function appendElemFromKey(object: any, key: string, element: any): boolean {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const walk = (obj: any, keys: string[], elem: any): boolean => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const newObj = obj[keys.shift()!];
if (!newObj) return false;
if (keys.length > 0) return walk(newObj, keys, elem);
(newObj as (typeof elem)[]).push(elem);
return true;
};
if (key.length === 0) return false;
return walk(object, key.split('.'), element);
}

/**
* リソースパスを取得します
* @param filePath 取得したいファイルのファイルパス
* @param datapackRoot データパックのルートパス
*/
export function getResourcePath(filePath: string, datapackRoot: string, fileType: FileType | undefined): string {
return path.relative(datapackRoot, filePath).replace(/\\/g, '/').replace(RegExp(`^data/([^/]+)/${fileType ? fileTypeFolderName[fileType] : '[^/]+'}/(.*)\\.(?:mcfunction|json)$`), '$1:$2');
export function getResourcePath(filePath: string, datapackRoot: string, fileType?: FileType): string {
const fileTypePath = getFilePath(fileType ?? getFileType(filePath, datapackRoot)) ?? '[^/]+';
return path.relative(datapackRoot, filePath).replace(/\\/g, '/').replace(RegExp(`^data/([^/]+)/${fileTypePath}/(.*)\\.(?:mcfunction|json)$`), '$1:$2');
}

/**
Expand Down
6 changes: 4 additions & 2 deletions src/utils/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ export async function pathAccessible(testPath: string | Uri): Promise<boolean> {
}

/**
* パスが存在するか、アクセス可能かを判別します
* @param testPath 確認するパス
* @license
* MIT License
*
Expand Down Expand Up @@ -90,4 +88,8 @@ export async function readFile(path: string): Promise<string> {
.on('end', () => resolve(data))
.on('error', reject);
});
}

export async function writeFile(path: string, content: string): Promise<void> {
return await fsp.writeFile(path, content);
}
5 changes: 5 additions & 0 deletions src/utils/vscodeWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ export function getTextEditor(): TextEditor {
return editor;
}

export function getIndent(path: string): number {
const config = workspace.getConfiguration('editor.tabSize', Uri.file(path));
return config.get<number>('tabSize', 4);
}

export async function listenInput(
message: string, validateInput?: (value: string) => Thenable<string | undefined> | string | undefined
): Promise<string> {
Expand Down

0 comments on commit 3ab0ebe

Please sign in to comment.