fodec 1.0.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/LICENSE +21 -0
- package/README.md +31 -0
- package/bin/fodec.js +14 -0
- package/lib/Fodec.d.ts +8 -0
- package/lib/Fodec.js +76 -0
- package/lib/cli/App.d.ts +12 -0
- package/lib/cli/App.js +109 -0
- package/lib/cli/index.d.ts +2 -0
- package/lib/cli/index.js +5 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +5 -0
- package/lib/types/Config.d.ts +26 -0
- package/lib/types/Config.js +2 -0
- package/lib/types/MapAlphabets.d.ts +27 -0
- package/lib/types/MapAlphabets.js +29 -0
- package/lib/utils/generateKey.d.ts +6 -0
- package/lib/utils/generateKey.js +25 -0
- package/lib/utils/shuffle.d.ts +1 -0
- package/lib/utils/shuffle.js +10 -0
- package/package.json +40 -0
- package/src/Fodec.ts +89 -0
- package/src/cli/App.ts +155 -0
- package/src/cli/index.ts +4 -0
- package/src/index.ts +1 -0
- package/src/types/Config.ts +28 -0
- package/src/types/MapAlphabets.ts +28 -0
- package/src/utils/generateKey.ts +39 -0
- package/src/utils/shuffle.ts +7 -0
- package/tsconfig.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Kris Papercut
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Fodec
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```shell
|
|
6
|
+
npm install -g fodec
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Initialization
|
|
10
|
+
|
|
11
|
+
This command generates a `fodec.json` file. You can further edit this file and add elements to the `resources` array.
|
|
12
|
+
|
|
13
|
+
```shell
|
|
14
|
+
fodec init
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Key generation
|
|
18
|
+
|
|
19
|
+
This command generates a `fodec.key` file for your project.
|
|
20
|
+
|
|
21
|
+
```shell
|
|
22
|
+
fodec gen
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Build
|
|
26
|
+
|
|
27
|
+
This command performs a build based on the provided `fodec.json` and `fodec.key` files. The build process takes the specifications and keys defined in these files to build the final output.
|
|
28
|
+
|
|
29
|
+
```shell
|
|
30
|
+
fodec build
|
|
31
|
+
```
|
package/bin/fodec.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const {app} = require("../lib/cli/index.js");
|
|
4
|
+
|
|
5
|
+
app.run().then((res) => {
|
|
6
|
+
if(!res) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
process.stdout.write(res);
|
|
11
|
+
process.stdout.write("\n");
|
|
12
|
+
}).catch((err) => {
|
|
13
|
+
process.stderr.write(err.message);
|
|
14
|
+
});
|
package/lib/Fodec.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare class Fodec {
|
|
2
|
+
protected key: string;
|
|
3
|
+
constructor(key: string);
|
|
4
|
+
transformText(str: string): string;
|
|
5
|
+
transformJson(data: any): Promise<any>;
|
|
6
|
+
transformFont(fontPath: string): Promise<string | ArrayBuffer | undefined>;
|
|
7
|
+
transformFontV1(fontPath: string): Promise<string | ArrayBuffer | undefined>;
|
|
8
|
+
}
|
package/lib/Fodec.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Fodec = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const fonteditor_core_1 = require("fonteditor-core");
|
|
10
|
+
class Fodec {
|
|
11
|
+
constructor(key) {
|
|
12
|
+
this.key = key;
|
|
13
|
+
}
|
|
14
|
+
transformText(str) {
|
|
15
|
+
return str.split("").map((char) => {
|
|
16
|
+
const index = this.key.indexOf(char);
|
|
17
|
+
return index !== -1 ? this.key.charAt(index + 1 + (this.key.length - 1) / 2) : char;
|
|
18
|
+
}).join("");
|
|
19
|
+
}
|
|
20
|
+
async transformJson(data) {
|
|
21
|
+
return data;
|
|
22
|
+
}
|
|
23
|
+
async transformFont(fontPath) {
|
|
24
|
+
return this.transformFontV1(fontPath);
|
|
25
|
+
}
|
|
26
|
+
async transformFontV1(fontPath) {
|
|
27
|
+
const ext = path_1.default.extname(fontPath).slice(1);
|
|
28
|
+
if (ext !== "ttf") {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const font = fonteditor_core_1.Font.create(await fs_1.promises.readFile(fontPath), {
|
|
32
|
+
type: ext
|
|
33
|
+
});
|
|
34
|
+
const { glyf: list, } = font.get();
|
|
35
|
+
const glyphs = [];
|
|
36
|
+
for (let i = 0; i < list.length; i++) {
|
|
37
|
+
const glyph = list[i];
|
|
38
|
+
const char = glyph.unicode
|
|
39
|
+
? String.fromCharCode(glyph.unicode[0])
|
|
40
|
+
: null;
|
|
41
|
+
if (!char) {
|
|
42
|
+
glyphs.push(glyph);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (this.key.indexOf(char) === -1) {
|
|
46
|
+
glyphs.push(glyph);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const index = this.key.indexOf(char);
|
|
50
|
+
const transformUnicode = this.key.charCodeAt((this.key.length - 1) / 2 + 1 + index);
|
|
51
|
+
const rand = list.find((item) => {
|
|
52
|
+
if (!item.unicode) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
return item.unicode[0] === transformUnicode;
|
|
56
|
+
});
|
|
57
|
+
if (!rand) {
|
|
58
|
+
glyphs.push(glyph);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
glyphs.push({
|
|
62
|
+
...glyph,
|
|
63
|
+
name: rand.name,
|
|
64
|
+
unicode: rand.unicode
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
font.set({
|
|
68
|
+
...font.get(),
|
|
69
|
+
glyf: glyphs
|
|
70
|
+
});
|
|
71
|
+
return font.write({
|
|
72
|
+
type: ext
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.Fodec = Fodec;
|
package/lib/cli/App.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Cli } from "@kearisp/cli";
|
|
2
|
+
import { Config } from "../types/Config";
|
|
3
|
+
export declare class App {
|
|
4
|
+
protected cli: Cli;
|
|
5
|
+
constructor();
|
|
6
|
+
protected getConfig(): Promise<Config>;
|
|
7
|
+
protected getKey(): Promise<string>;
|
|
8
|
+
init(): Promise<void>;
|
|
9
|
+
generate(): Promise<void>;
|
|
10
|
+
build(): Promise<void>;
|
|
11
|
+
run(): Promise<any>;
|
|
12
|
+
}
|
package/lib/cli/App.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.App = void 0;
|
|
7
|
+
const cli_1 = require("@kearisp/cli");
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const utils_1 = require("@wocker/utils");
|
|
11
|
+
const Fodec_1 = require("../Fodec");
|
|
12
|
+
const generateKey_1 = require("../utils/generateKey");
|
|
13
|
+
class App {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.cli = new cli_1.Cli();
|
|
16
|
+
this.cli.command("init")
|
|
17
|
+
.action(() => this.init());
|
|
18
|
+
this.cli.command("gen")
|
|
19
|
+
.action(() => this.generate());
|
|
20
|
+
this.cli.command("build")
|
|
21
|
+
.action(() => this.build());
|
|
22
|
+
}
|
|
23
|
+
async getConfig() {
|
|
24
|
+
const configPath = "fodec.json";
|
|
25
|
+
if (!(0, fs_1.existsSync)(configPath)) {
|
|
26
|
+
throw new Error("Config not found");
|
|
27
|
+
}
|
|
28
|
+
const res = await fs_1.promises.readFile(configPath);
|
|
29
|
+
return JSON.parse(res.toString());
|
|
30
|
+
}
|
|
31
|
+
async getKey() {
|
|
32
|
+
const res = await fs_1.promises.readFile("fodec.key");
|
|
33
|
+
return res.toString();
|
|
34
|
+
}
|
|
35
|
+
async init() {
|
|
36
|
+
const configPath = "./fodec-2.json";
|
|
37
|
+
if ((0, fs_1.existsSync)(configPath)) {
|
|
38
|
+
throw new Error("Config already exists");
|
|
39
|
+
}
|
|
40
|
+
let config = {};
|
|
41
|
+
config.basePath = await (0, utils_1.promptText)({
|
|
42
|
+
required: true,
|
|
43
|
+
type: "string",
|
|
44
|
+
message: "Base Path:",
|
|
45
|
+
default: "src"
|
|
46
|
+
});
|
|
47
|
+
config.output = {
|
|
48
|
+
path: await (0, utils_1.promptText)({
|
|
49
|
+
required: true,
|
|
50
|
+
type: "string",
|
|
51
|
+
message: "Output path:",
|
|
52
|
+
default: "build"
|
|
53
|
+
})
|
|
54
|
+
};
|
|
55
|
+
config.alphabets = await (0, utils_1.promptSelect)({
|
|
56
|
+
multiple: true,
|
|
57
|
+
options: [
|
|
58
|
+
"cyrillic",
|
|
59
|
+
"latin"
|
|
60
|
+
]
|
|
61
|
+
});
|
|
62
|
+
config.resources = [];
|
|
63
|
+
await fs_1.promises.writeFile(configPath, JSON.stringify(config, null, 4));
|
|
64
|
+
}
|
|
65
|
+
async generate() {
|
|
66
|
+
const { alphabets } = await this.getConfig();
|
|
67
|
+
const key = (0, generateKey_1.generateKey)({
|
|
68
|
+
alphabets
|
|
69
|
+
});
|
|
70
|
+
console.log(key);
|
|
71
|
+
await fs_1.promises.writeFile("fodec.key", key);
|
|
72
|
+
}
|
|
73
|
+
async build() {
|
|
74
|
+
const key = await this.getKey();
|
|
75
|
+
const { basePath = "./", output: { path: outPath = "./build" } = {}, fonts, resources } = await this.getConfig();
|
|
76
|
+
const fodec = new Fodec_1.Fodec(key);
|
|
77
|
+
for (const resource of resources) {
|
|
78
|
+
let res;
|
|
79
|
+
if (resource.type === "font") {
|
|
80
|
+
const transformedFont = await fodec.transformFont(path_1.default.join(basePath, resource.path));
|
|
81
|
+
if (!transformedFont || transformedFont instanceof ArrayBuffer) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
res = transformedFont;
|
|
85
|
+
}
|
|
86
|
+
else if (resource.type === "json") {
|
|
87
|
+
const json = await fs_1.promises.readFile(path_1.default.join(basePath, resource.path));
|
|
88
|
+
const data = JSON.parse(json.toString());
|
|
89
|
+
res = JSON.stringify(data, (key, value) => {
|
|
90
|
+
if (typeof value === "string") {
|
|
91
|
+
return fodec.transformText(value);
|
|
92
|
+
}
|
|
93
|
+
return value;
|
|
94
|
+
}, 4);
|
|
95
|
+
}
|
|
96
|
+
if (res) {
|
|
97
|
+
const outFullPath = path_1.default.join(outPath, path_1.default.dirname(resource.output || resource.path));
|
|
98
|
+
(0, fs_1.mkdirSync)(outFullPath, {
|
|
99
|
+
recursive: true
|
|
100
|
+
});
|
|
101
|
+
await fs_1.promises.writeFile(path_1.default.join(outPath, resource.output || resource.path), res);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async run() {
|
|
106
|
+
return this.cli.run(process.argv);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.App = App;
|
package/lib/cli/index.js
ADDED
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Fodec } from "./Fodec";
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AlphabetType } from "./MapAlphabets";
|
|
2
|
+
export type Config = {
|
|
3
|
+
basePath?: string;
|
|
4
|
+
output?: {
|
|
5
|
+
path: string;
|
|
6
|
+
};
|
|
7
|
+
alphabets: AlphabetType[];
|
|
8
|
+
fonts: {
|
|
9
|
+
name: string;
|
|
10
|
+
path: string;
|
|
11
|
+
}[];
|
|
12
|
+
resources: (FontResource | JsonResource)[];
|
|
13
|
+
};
|
|
14
|
+
type FontResource = {
|
|
15
|
+
type: "font";
|
|
16
|
+
format: string;
|
|
17
|
+
name: string;
|
|
18
|
+
path: string;
|
|
19
|
+
output?: string;
|
|
20
|
+
};
|
|
21
|
+
type JsonResource = {
|
|
22
|
+
type: "json";
|
|
23
|
+
path: string;
|
|
24
|
+
output?: string;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const MapAlphabets: {
|
|
2
|
+
latin: {
|
|
3
|
+
lowerStart: number;
|
|
4
|
+
lowerLength: number;
|
|
5
|
+
upperStart: number;
|
|
6
|
+
upperLength: number;
|
|
7
|
+
};
|
|
8
|
+
cyrillic: {
|
|
9
|
+
lowerStart: number;
|
|
10
|
+
lowerLength: number;
|
|
11
|
+
upperStart: number;
|
|
12
|
+
upperLength: number;
|
|
13
|
+
};
|
|
14
|
+
arabic: {
|
|
15
|
+
lowerStart: number;
|
|
16
|
+
lowerLength: number;
|
|
17
|
+
upperStart: number;
|
|
18
|
+
upperLength: number;
|
|
19
|
+
};
|
|
20
|
+
greek: {
|
|
21
|
+
lowerStart: number;
|
|
22
|
+
lowerLength: number;
|
|
23
|
+
upperStart: number;
|
|
24
|
+
upperLength: number;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export type AlphabetType = keyof typeof MapAlphabets;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MapAlphabets = void 0;
|
|
4
|
+
exports.MapAlphabets = {
|
|
5
|
+
latin: {
|
|
6
|
+
lowerStart: 0x61,
|
|
7
|
+
lowerLength: 26,
|
|
8
|
+
upperStart: 0x41,
|
|
9
|
+
upperLength: 26
|
|
10
|
+
},
|
|
11
|
+
cyrillic: {
|
|
12
|
+
lowerStart: 0x430,
|
|
13
|
+
lowerLength: 32,
|
|
14
|
+
upperStart: 0x410,
|
|
15
|
+
upperLength: 32
|
|
16
|
+
},
|
|
17
|
+
arabic: {
|
|
18
|
+
lowerStart: 0x0620,
|
|
19
|
+
lowerLength: 36,
|
|
20
|
+
upperStart: 0x0620,
|
|
21
|
+
upperLength: 36
|
|
22
|
+
},
|
|
23
|
+
greek: {
|
|
24
|
+
lowerStart: 0x03B1,
|
|
25
|
+
lowerLength: 25,
|
|
26
|
+
upperStart: 0x0391,
|
|
27
|
+
upperLength: 25
|
|
28
|
+
}
|
|
29
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateKey = void 0;
|
|
4
|
+
const shuffle_1 = require("./shuffle");
|
|
5
|
+
const MapAlphabets_1 = require("../types/MapAlphabets");
|
|
6
|
+
const generateKey = (options) => {
|
|
7
|
+
const { alphabets } = options;
|
|
8
|
+
return Object.keys(MapAlphabets_1.MapAlphabets).reduce((res, key) => {
|
|
9
|
+
if (!alphabets.includes(key)) {
|
|
10
|
+
return res;
|
|
11
|
+
}
|
|
12
|
+
const { lowerStart, lowerLength, upperStart, upperLength } = MapAlphabets_1.MapAlphabets[key];
|
|
13
|
+
const indexes = [
|
|
14
|
+
...Array.from({ length: lowerLength }, (_, i) => lowerStart + i),
|
|
15
|
+
...Array.from({ length: upperLength }, (_, i) => upperStart + i)
|
|
16
|
+
];
|
|
17
|
+
const moved = indexes.slice();
|
|
18
|
+
(0, shuffle_1.shuffle)(moved);
|
|
19
|
+
return [
|
|
20
|
+
res[0] + String.fromCharCode(...indexes),
|
|
21
|
+
res[1] + String.fromCharCode(...moved)
|
|
22
|
+
];
|
|
23
|
+
}, ["", ""]).join("\n");
|
|
24
|
+
};
|
|
25
|
+
exports.generateKey = generateKey;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const shuffle: (arr: unknown[]) => void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shuffle = void 0;
|
|
4
|
+
const shuffle = (arr) => {
|
|
5
|
+
for (let i = arr.length - 1; i > 0; i--) {
|
|
6
|
+
let j = Math.floor(Math.random() * (i + 1));
|
|
7
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
exports.shuffle = shuffle;
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fodec",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "Kris Papercut <krispcut@gmail.com>",
|
|
5
|
+
"description": "",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "lib/index.js",
|
|
8
|
+
"types": "lib/index.d.ts",
|
|
9
|
+
"directories": {
|
|
10
|
+
"cli": "./lib/cli"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"fodec": "./bin/fodec.js"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"prepare": "npm run build",
|
|
17
|
+
"build": "tsc --build",
|
|
18
|
+
"watch": "tsc --watch",
|
|
19
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/kearisp/fodec#readme",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/kearisp/fodec.git"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/kearisp/fodec/issues"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@kearisp/cli": "^1.0.4",
|
|
31
|
+
"@wocker/utils": "^1.0.2",
|
|
32
|
+
"fonteditor-core": "^2.3.2",
|
|
33
|
+
"fs": "^0.0.1-security",
|
|
34
|
+
"path": "^0.12.7"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^20.11.5",
|
|
38
|
+
"typescript": "^5.3.3"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/Fodec.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import Path from "path";
|
|
2
|
+
import {promises as FS} from "fs";
|
|
3
|
+
import {Font, TTF} from "fonteditor-core";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class Fodec {
|
|
7
|
+
public constructor(
|
|
8
|
+
protected key: string
|
|
9
|
+
) {}
|
|
10
|
+
|
|
11
|
+
public transformText(str: string): string {
|
|
12
|
+
return str.split("").map((char) => {
|
|
13
|
+
const index = this.key.indexOf(char);
|
|
14
|
+
|
|
15
|
+
return index !== -1 ? this.key.charAt(index + 1 + (this.key.length - 1) / 2) : char;
|
|
16
|
+
}).join("");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public async transformJson(data: any) {
|
|
20
|
+
return data;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public async transformFont(fontPath: string) {
|
|
24
|
+
return this.transformFontV1(fontPath);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public async transformFontV1(fontPath: string) {
|
|
28
|
+
const ext = Path.extname(fontPath).slice(1);
|
|
29
|
+
|
|
30
|
+
if(ext !== "ttf") {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const font = Font.create(await FS.readFile(fontPath), {
|
|
35
|
+
type: ext
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const {glyf: list,} = font.get();
|
|
39
|
+
const glyphs: TTF.Glyph[] = [];
|
|
40
|
+
|
|
41
|
+
for(let i = 0; i < list.length; i++) {
|
|
42
|
+
const glyph = list[i];
|
|
43
|
+
const char = glyph.unicode
|
|
44
|
+
? String.fromCharCode(glyph.unicode[0])
|
|
45
|
+
: null;
|
|
46
|
+
|
|
47
|
+
if(!char) {
|
|
48
|
+
glyphs.push(glyph);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if(this.key.indexOf(char) === -1) {
|
|
53
|
+
glyphs.push(glyph);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const index = this.key.indexOf(char);
|
|
58
|
+
const transformUnicode = this.key.charCodeAt((this.key.length - 1) / 2 + 1 + index);
|
|
59
|
+
|
|
60
|
+
const rand = list.find((item) => {
|
|
61
|
+
if(!item.unicode) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return item.unicode[0] === transformUnicode;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if(!rand) {
|
|
69
|
+
glyphs.push(glyph);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
glyphs.push({
|
|
74
|
+
...glyph,
|
|
75
|
+
name: rand.name,
|
|
76
|
+
unicode: rand.unicode
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
font.set({
|
|
81
|
+
...font.get(),
|
|
82
|
+
glyf: glyphs
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return font.write({
|
|
86
|
+
type: ext
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
package/src/cli/App.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import {Cli} from "@kearisp/cli";
|
|
2
|
+
import {promises as FS, existsSync, mkdirSync} from "fs";
|
|
3
|
+
import Path from "path";
|
|
4
|
+
import {promptText, promptSelect} from "@wocker/utils";
|
|
5
|
+
import {Fodec} from "../Fodec";
|
|
6
|
+
import {generateKey} from "../utils/generateKey";
|
|
7
|
+
import {Config} from "../types/Config";
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export class App {
|
|
11
|
+
protected cli: Cli;
|
|
12
|
+
|
|
13
|
+
public constructor() {
|
|
14
|
+
this.cli = new Cli();
|
|
15
|
+
|
|
16
|
+
this.cli.command("init")
|
|
17
|
+
.action(() => this.init());
|
|
18
|
+
|
|
19
|
+
this.cli.command("gen")
|
|
20
|
+
.action(() => this.generate());
|
|
21
|
+
|
|
22
|
+
this.cli.command("build")
|
|
23
|
+
.action(() => this.build());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
protected async getConfig(): Promise<Config> {
|
|
27
|
+
const configPath = "fodec.json";
|
|
28
|
+
|
|
29
|
+
if(!existsSync(configPath)) {
|
|
30
|
+
throw new Error("Config not found");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const res = await FS.readFile(configPath);
|
|
34
|
+
|
|
35
|
+
return JSON.parse(res.toString());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
protected async getKey(): Promise<string> {
|
|
39
|
+
const res = await FS.readFile("fodec.key");
|
|
40
|
+
|
|
41
|
+
return res.toString();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public async init() {
|
|
45
|
+
const configPath = "./fodec-2.json";
|
|
46
|
+
|
|
47
|
+
if(existsSync(configPath)) {
|
|
48
|
+
throw new Error("Config already exists");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let config: Config = {} as Config;
|
|
52
|
+
|
|
53
|
+
config.basePath = await promptText({
|
|
54
|
+
required: true,
|
|
55
|
+
type: "string",
|
|
56
|
+
message: "Base Path:",
|
|
57
|
+
default: "src"
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
config.output = {
|
|
61
|
+
path: await promptText({
|
|
62
|
+
required: true,
|
|
63
|
+
type: "string",
|
|
64
|
+
message: "Output path:",
|
|
65
|
+
default: "build"
|
|
66
|
+
})
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
config.alphabets = await promptSelect({
|
|
70
|
+
multiple: true,
|
|
71
|
+
options: [
|
|
72
|
+
"cyrillic",
|
|
73
|
+
"latin"
|
|
74
|
+
]
|
|
75
|
+
}) as Config["alphabets"];
|
|
76
|
+
|
|
77
|
+
config.resources = [];
|
|
78
|
+
|
|
79
|
+
await FS.writeFile(configPath, JSON.stringify(config, null, 4));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public async generate() {
|
|
83
|
+
const {alphabets} = await this.getConfig();
|
|
84
|
+
|
|
85
|
+
const key = generateKey({
|
|
86
|
+
alphabets
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
console.log(key);
|
|
90
|
+
|
|
91
|
+
await FS.writeFile("fodec.key", key);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public async build(): Promise<void> {
|
|
95
|
+
const key = await this.getKey();
|
|
96
|
+
const {
|
|
97
|
+
basePath = "./",
|
|
98
|
+
output: {
|
|
99
|
+
path: outPath = "./build"
|
|
100
|
+
} = {},
|
|
101
|
+
fonts,
|
|
102
|
+
resources
|
|
103
|
+
} = await this.getConfig();
|
|
104
|
+
|
|
105
|
+
const fodec = new Fodec(key);
|
|
106
|
+
|
|
107
|
+
for(const resource of resources) {
|
|
108
|
+
let res: any;
|
|
109
|
+
|
|
110
|
+
if(resource.type === "font") {
|
|
111
|
+
const transformedFont = await fodec.transformFont(
|
|
112
|
+
Path.join(basePath, resource.path)
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if(!transformedFont || transformedFont instanceof ArrayBuffer) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
res = transformedFont;
|
|
120
|
+
}
|
|
121
|
+
else if(resource.type === "json") {
|
|
122
|
+
const json = await FS.readFile(
|
|
123
|
+
Path.join(basePath, resource.path)
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const data = JSON.parse(json.toString());
|
|
127
|
+
|
|
128
|
+
res = JSON.stringify(data, (key, value) => {
|
|
129
|
+
if(typeof value === "string") {
|
|
130
|
+
return fodec.transformText(value);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return value;
|
|
134
|
+
}, 4);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if(res) {
|
|
138
|
+
const outFullPath = Path.join(outPath, Path.dirname(resource.output || resource.path));
|
|
139
|
+
|
|
140
|
+
mkdirSync(outFullPath, {
|
|
141
|
+
recursive: true
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
await FS.writeFile(
|
|
145
|
+
Path.join(outPath, resource.output || resource.path),
|
|
146
|
+
res
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public async run() {
|
|
153
|
+
return this.cli.run(process.argv);
|
|
154
|
+
}
|
|
155
|
+
}
|
package/src/cli/index.ts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {Fodec} from "./Fodec";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {AlphabetType} from "./MapAlphabets";
|
|
2
|
+
|
|
3
|
+
export type Config = {
|
|
4
|
+
basePath?: string;
|
|
5
|
+
output?: {
|
|
6
|
+
path: string;
|
|
7
|
+
};
|
|
8
|
+
alphabets: AlphabetType[];
|
|
9
|
+
fonts: {
|
|
10
|
+
name: string;
|
|
11
|
+
path: string;
|
|
12
|
+
}[];
|
|
13
|
+
resources: (FontResource | JsonResource)[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type FontResource = {
|
|
17
|
+
type: "font",
|
|
18
|
+
format: string;
|
|
19
|
+
name: string;
|
|
20
|
+
path: string;
|
|
21
|
+
output?: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type JsonResource = {
|
|
25
|
+
type: "json",
|
|
26
|
+
path: string;
|
|
27
|
+
output?: string;
|
|
28
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const MapAlphabets = {
|
|
2
|
+
latin: {
|
|
3
|
+
lowerStart: 0x61,
|
|
4
|
+
lowerLength: 26,
|
|
5
|
+
upperStart: 0x41,
|
|
6
|
+
upperLength: 26
|
|
7
|
+
},
|
|
8
|
+
cyrillic: {
|
|
9
|
+
lowerStart: 0x430,
|
|
10
|
+
lowerLength: 32,
|
|
11
|
+
upperStart: 0x410,
|
|
12
|
+
upperLength: 32
|
|
13
|
+
},
|
|
14
|
+
arabic: {
|
|
15
|
+
lowerStart: 0x0620,
|
|
16
|
+
lowerLength: 36,
|
|
17
|
+
upperStart: 0x0620,
|
|
18
|
+
upperLength: 36
|
|
19
|
+
},
|
|
20
|
+
greek: {
|
|
21
|
+
lowerStart: 0x03B1,
|
|
22
|
+
lowerLength: 25,
|
|
23
|
+
upperStart: 0x0391,
|
|
24
|
+
upperLength: 25
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type AlphabetType = keyof typeof MapAlphabets;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {shuffle} from "./shuffle";
|
|
2
|
+
import {MapAlphabets, AlphabetType} from "../types/MapAlphabets";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
type Options = {
|
|
6
|
+
alphabets: AlphabetType[];
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const generateKey = (options: Options): string => {
|
|
10
|
+
const {
|
|
11
|
+
alphabets
|
|
12
|
+
} = options;
|
|
13
|
+
|
|
14
|
+
return Object.keys(MapAlphabets).reduce((res: string[], key: string) => {
|
|
15
|
+
if(!alphabets.includes(key as AlphabetType)) {
|
|
16
|
+
return res;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
lowerStart,
|
|
21
|
+
lowerLength,
|
|
22
|
+
upperStart,
|
|
23
|
+
upperLength
|
|
24
|
+
} = MapAlphabets[key];
|
|
25
|
+
|
|
26
|
+
const indexes = [
|
|
27
|
+
...Array.from({length: lowerLength}, (_, i) => lowerStart + i),
|
|
28
|
+
...Array.from({length: upperLength}, (_, i) => upperStart + i)
|
|
29
|
+
];
|
|
30
|
+
const moved = indexes.slice();
|
|
31
|
+
|
|
32
|
+
shuffle(moved);
|
|
33
|
+
|
|
34
|
+
return [
|
|
35
|
+
res[0] + String.fromCharCode(...indexes),
|
|
36
|
+
res[1] + String.fromCharCode(...moved)
|
|
37
|
+
];
|
|
38
|
+
}, ["", ""]).join("\n");
|
|
39
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"allowJs": true,
|
|
4
|
+
"allowSyntheticDefaultImports": true,
|
|
5
|
+
"baseUrl": ".",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"isolatedModules": true,
|
|
10
|
+
"lib": [
|
|
11
|
+
"dom",
|
|
12
|
+
"dom.iterable",
|
|
13
|
+
"esnext"
|
|
14
|
+
],
|
|
15
|
+
"module": "CommonJS",
|
|
16
|
+
"moduleResolution": "node",
|
|
17
|
+
"noEmit": false,
|
|
18
|
+
"noFallthroughCasesInSwitch": true,
|
|
19
|
+
"noImplicitAny": false,
|
|
20
|
+
"outDir": "./lib",
|
|
21
|
+
"resolveJsonModule": true,
|
|
22
|
+
"skipLibCheck": true,
|
|
23
|
+
"strict": true,
|
|
24
|
+
"target": "ES2020",
|
|
25
|
+
"typeRoots": [
|
|
26
|
+
"./node_modules/@types"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"exclude": [
|
|
30
|
+
"node_modules",
|
|
31
|
+
"lib",
|
|
32
|
+
"./**/__tests__/*"
|
|
33
|
+
],
|
|
34
|
+
"include": [
|
|
35
|
+
"src/**/*"
|
|
36
|
+
]
|
|
37
|
+
}
|