Skip to content

Commit

Permalink
生成Lua插件
Browse files Browse the repository at this point in the history
  • Loading branch information
sumneko committed Jul 26, 2024
1 parent bd52fb4 commit 11a8762
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { download } from './download';
export { log } from './log';
export * as fs from './fs';
export * as json from './json';
export * as lua from './lua';
9 changes: 9 additions & 0 deletions src/tools/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,12 @@ export class Json {
this._patch = undefined;
}
}

/**
* 解析json文本,支持注释和尾随逗号
* @param text json文本
* @returns
*/
export function parse(text: string) {
return jsonc.parse(text, undefined, parseOptions);
}
189 changes: 189 additions & 0 deletions src/tools/lua.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
const encodeOptions = {
newline: '\n',
indent: ' ',
depth: 0,
} as const;

class Encoder {
private buffer: string[] = [];
public newline = encodeOptions.newline;
public indent = encodeOptions.indent;
public depth = 0;

constructor() {}

public encode(jsObject: any) {
this.buffer = [];

this.encodeValue(jsObject);

return this.buffer.join("");
}

private encodeValue(value: any) {
switch (value) {
case undefined:
this.encodeUndefined();
return;
case null:
this.encodeNull();
return;
case true:
this.encodeTrue();
return;
case false:
this.encodeFalse();
return;
}

switch (typeof value) {
case 'string':
this.encodeString(value);
return;
case 'number':
this.encodeNumber(value);
return;
case 'object':
this.encodeObject(value);
return;
}

this.encodeString(String(value));
}

private encodeUndefined() {
this.buffer.push('nil');
}

private encodeNull() {
this.buffer.push('nil');
}

private encodeTrue() {
this.buffer.push('true');
}

private encodeFalse() {
this.buffer.push('false');
}

private encodeString(value: string) {
// 字符串中换行符的数量
let nlNum = value.match('\n')?.length ?? 0;
// 字符串中控制字符和不可见字符的数量,但不包括制表符、换行符
let ccNum = value.match(/[\x00-\x08\x0B-\x1F\x7F-\x9F]/)?.length ?? 0;
if (ccNum <= nlNum && nlNum > 0) {
this.encodeLongString(value);
} else {
this.encodeShortString(value);
}
}

private encodeLongString(value: string) {
let end = ']]';
while (value.includes(end)) {
end = end.slice(0, -2) + '=]';
}
let start = '[' + end.slice(1, -2) + '[';
this.buffer.push(start, this.newline, value, end);
}

private encodeShortString(value: string) {
let singleNum = value.match(/'/)?.length ?? 0;
let doubleNum = value.match(/"/)?.length ?? 0;
let delim = doubleNum > singleNum ? "'" : '"';

let reg = new RegExp(`[${delim}\\\x00-\x08\x0B-\x1F\x7F-\x9F]`, 'g');
value = value.replaceAll(reg, (match) => {
if (match === delim || match === '\\') {
return '\\' + delim;
} else {
return `\\x${match.charCodeAt(0).toString(16).padStart(2, '0')}`;
}
});
this.buffer.push(delim, value, delim);
}

private encodeNumber(value: number) {
if (Number.isInteger(value)) {
this.buffer.push(value.toString());
} else if (value === Infinity) {
this.buffer.push('1/0');
} else if (value === -Infinity) {
this.buffer.push('-1/0');
} else if (Number.isNaN(value)) {
this.buffer.push('0/0');
} else {
let str = value.toString();
if (!str.includes('.') && !str.includes('e')) {
str += '.0';
}
this.buffer.push(str);
}
}

private encodeArray(value: any[]) {
if (value.length === 0) {
this.buffer.push('{}');
} else if (value.length <= 5) {
this.buffer.push('{ ');
for (let i = 0; i < value.length; i++) {
if (i > 0) {
this.buffer.push(', ');
}
this.encodeValue(value[i]);
}
this.buffer.push(' }');
} else {
this.buffer.push('{', this.newline);
this.depth++;
for (let i = 0; i < value.length; i++) {
this.buffer.push(this.indent.repeat(this.depth));
this.encodeValue(value[i]);
this.buffer.push(',', this.newline);
}
this.depth--;
this.buffer.push(this.indent.repeat(this.depth));
this.buffer.push('}');
}
}

private encodeTable(value: { [key: string]: any }) {
this.buffer.push('{', this.newline);
this.depth++;
for (const [k, v] of Object.entries(value)) {
this.buffer.push(this.indent.repeat(this.depth));
if (k.match(/^[_\p{L}][_\p{L}\p{N}]*$/u)) {
this.buffer.push(k);
} else {
this.buffer.push('[');
this.encodeString(k);
this.buffer.push(']');
}
this.buffer.push(' = ');
this.encodeValue(v);
this.buffer.push(',', this.newline);
}
this.depth--;
this.buffer.push(this.indent.repeat(this.depth));
this.buffer.push('}');
}

private encodeObject(value: Object) {
if (Array.isArray(value)) {
this.encodeArray(value);
} else {
this.encodeTable(value);
}
}
}



export function encode(jsObject: any, options?: Partial<typeof encodeOptions>) {
let encoder = new Encoder();
if (options) {
Object.assign(encoder, options);
}
return encoder.encode(jsObject);
}
17 changes: 14 additions & 3 deletions template/plugin/y3-helper.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3030,6 +3030,13 @@ declare class Json {
set(key: string, value: any): boolean;
private applyPatch;
}
declare function parse(text: string): any;
declare const encodeOptions: {
readonly newline: "\n";
readonly indent: " ";
readonly depth: 0;
};
declare function encode(jsObject: any, options?: Partial<typeof encodeOptions>): string;
export type EditorVersion = "1.0" | "2.0" | "unknown";
declare class Env {
private envChangeEmitter;
Expand Down Expand Up @@ -3109,8 +3116,8 @@ export declare function openInExplorer(uri: vscode.Uri | string): void;
export declare function sleep(ms: number): Promise<void>;
export declare function assert(exp: any, msg?: string): void;

declare namespace json {
export { Item, JArray, JObject, Json };
declare namespace lua {
export { encode };
}
declare namespace plugin {
export { init$3 as init, onceDidRun, runAllPlugins };
Expand All @@ -3127,11 +3134,14 @@ declare namespace language {
declare namespace fs {
export { copy, dir, isAbsolutePath, isDirectory, isExists, isFile, isRelativePath, readFile, removeFile, scan, stat, writeFile };
}
declare namespace json {
export { Item, JArray, JObject, Json, parse };
}
declare namespace consts {
export { CSV, Table$1 as Table, Template };
}
declare namespace y3 {
export { consts, excel, fs, json, language, plugin, table };
export { consts, excel, fs, json, language, lua, plugin, table };
}

export {
Expand All @@ -3140,6 +3150,7 @@ export {
fs,
json,
language,
lua,
plugin,
table,
};
Expand Down

0 comments on commit 11a8762

Please sign in to comment.