v-transform 1.1.0 → 2.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/package.json CHANGED
@@ -4,13 +4,14 @@
4
4
  "vt": "src/index.js"
5
5
  },
6
6
  "type": "module",
7
- "version": "1.1.0",
7
+ "version": "2.0.0",
8
8
  "main": "index.js",
9
9
  "repository": "https://github.com/VickScarlet/vTransform.git",
10
10
  "author": "Vick Scarlet <scarlet_vick@outlook.com>",
11
11
  "license": "MIT",
12
12
  "dependencies": {
13
13
  "commander": "^8.2.0",
14
+ "glob": "^8.0.3",
14
15
  "js-yaml": "^4.1.0",
15
16
  "xlsx": "^0.17.1"
16
17
  }
package/src/dump.js ADDED
@@ -0,0 +1,63 @@
1
+ import yaml from 'js-yaml';
2
+ import path from 'path';
3
+ import { writeFile, stat, mkdir } from 'fs/promises';
4
+
5
+ function jsonify(data, space) {
6
+ return JSON.stringify(data, null, space);
7
+ }
8
+
9
+ function cjsify(data, space) {
10
+ return `module.exports = ${jsonify(data, space)}`;
11
+ }
12
+
13
+ function esmify(data, space) {
14
+ return `export default ${jsonify(data, space)}`;
15
+ }
16
+
17
+ function yamlify(data, space) {
18
+ return yaml.dump(data, {
19
+ indent: space || undefined,
20
+ });
21
+ }
22
+
23
+ async function mkdirs(dir) {
24
+ try {
25
+ await stat(dir);
26
+ } catch(e) {
27
+ await mkdirs(path.dirname(dir));
28
+ mkdir(dir);
29
+ }
30
+ };
31
+
32
+ async function write(sheet, data) {
33
+ console.info(`Dump ${sheet}`);
34
+ await mkdirs(path.dirname(sheet));
35
+ await writeFile(sheet, data);
36
+ }
37
+
38
+ export async function dump(sheet, data, type, space) {
39
+ let ext, ify;
40
+ switch(type) {
41
+ case 'cjs':
42
+ ext = '.js';
43
+ ify = cjsify;
44
+ break;
45
+ case 'js':
46
+ case 'mjs':
47
+ case 'esm':
48
+ ext = '.js';
49
+ ify = esmify;
50
+ break;
51
+ case 'yaml':
52
+ case 'yml':
53
+ ext = '.yaml';
54
+ ify = yamlify;
55
+ break;
56
+ case 'json':
57
+ default:
58
+ ext = '.json';
59
+ ify = jsonify;
60
+ break;
61
+ }
62
+ return write(`${sheet}${ext}`, ify(data, space));
63
+ }
package/src/index.js CHANGED
@@ -1,8 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
3
  import { readFile } from 'fs/promises';
4
- import { read, getWrite, jobs as getJobs } from './io.js';
5
- import { jobs as doJobs } from './transform/index.js';
4
+ import { transform } from './transform.js';
6
5
 
7
6
  (async() => {
8
7
 
@@ -14,9 +13,15 @@ program
14
13
  .command('transform [list...]')
15
14
  .option('-t, --type <type>', 'type of transform, available: js, esm, cjs, json', 'json')
16
15
  .option('-s, --space <space>', 'format space number', 0)
17
- .action(async (list, {type, space}) => doJobs(
18
- await getJobs(list), read, getWrite(type, space),
19
- ));
16
+ .option('-c, --config <config>', 'configure file', null)
17
+ .option('-w, --cwd <cwd>', 'current work dir', null)
18
+ .option('-o, --output <output>', 'output dir', null)
19
+ .option('-d, --dest <dest>', 'dest dir', null)
20
+ .action((list, options) => {
21
+ if(!options.dest) options.dest = options.output;
22
+ options.list = list;
23
+ transform(options);
24
+ });
20
25
 
21
26
  program.parse(process.argv);
22
27
 
package/src/loader.js ADDED
@@ -0,0 +1,67 @@
1
+ import glob from 'glob';
2
+ import yaml from 'js-yaml';
3
+ import path from 'path';
4
+ import { readFile } from 'fs/promises';
5
+
6
+ export async function load({type, space, config, dest, list, cwd}) {
7
+ type = type || 'json';
8
+ cwd = cwd || process.cwd();
9
+ space = Number(space) || 0;
10
+ dest = dest || cwd;
11
+ const def = {cwd, type, space, dest};
12
+ const m = (...l)=>globit(Object.assign({}, ...l));
13
+ const cfgs = [];
14
+
15
+ if(list?.length)
16
+ cfgs.unshift(await m(def, {glob: list}));
17
+
18
+ if(config) {
19
+ const c = await loadConfig(config);
20
+ const dir = path.dirname(config);
21
+ const cdef = {};
22
+ if(c.cwd) cdef.cwd = path.resolve(dir, c.cwd);
23
+ if(c.type) cdef.type = c.type;
24
+ if(typeof c.space == 'number') cdef.space = c.space;
25
+ if(c.dest) cdef.dest = path.resolve(dir, c.dest);
26
+ for(const cfg of c.configurations) {
27
+ if(cfg.cwd) cfg.cwd = path.resolve(dir, cfg.cwd);
28
+ if(cfg.dest) cfg.dest = path.resolve(dir, cfg.dest);
29
+ cfgs.push(await m(def, cdef, cfg));
30
+ }
31
+ }
32
+
33
+ return cfgs;
34
+ }
35
+
36
+ async function loadConfig(config) {
37
+ switch(path.extname(config)) {
38
+ case '.json':
39
+ case '.yaml':
40
+ case '.yml':
41
+ return yaml.load(
42
+ await readFile(config)
43
+ );
44
+ case '.js':
45
+ case '.mjs':
46
+ return (await import(config)).default;
47
+ default:
48
+ throw new Error(`Unknown config file type: ${config}`);
49
+ }
50
+ }
51
+
52
+ async function globit(options) {
53
+ const {glob: gs, cwd} = options;
54
+ const files = [];
55
+ const g = p=>new Promise(r=>glob(
56
+ p, {cwd}, (err, files) => r(err?[]:files)
57
+ ))
58
+ if(Array.isArray(gs))
59
+ for(const p of gs)
60
+ files.push(...await g(p));
61
+ else if(typeof gs == 'string')
62
+ files.push(...await g(gs));
63
+ else
64
+ throw new Error(`Unknown glob type: ${gs}`);
65
+
66
+ return Object.assign({files}, options);
67
+ }
File without changes
package/src/prepare.js ADDED
@@ -0,0 +1,26 @@
1
+ import path from 'path';
2
+ import { readFile } from 'fs/promises';
3
+ import * as XLSX from 'xlsx';
4
+
5
+ export async function prepare(xlsxPath) {
6
+ switch(path.extname(xlsxPath)) {
7
+ case '.xls':
8
+ case '.xlsx':
9
+ break;
10
+ default:
11
+ return [];
12
+ }
13
+ const xlsxFileBuffer = await readFile(xlsxPath);
14
+ const xlsx = XLSX.read(xlsxFileBuffer, {type: 'buffer'});
15
+ const sheets = xlsx.Sheets;
16
+ const data = [];
17
+ for(const sheetName in sheets) {
18
+ const sheetRawData = sheets[sheetName];
19
+ if(!sheetRawData['!ref']) break;
20
+ data.push({
21
+ name: sheetName,
22
+ data: XLSX.utils.sheet_to_json(sheetRawData, { header: 1 })
23
+ });
24
+ }
25
+ return data;
26
+ }
@@ -0,0 +1,60 @@
1
+ import path from 'path';
2
+ import { load } from './loader.js';
3
+ import { prepare } from './prepare.js';
4
+ import { parser } from './parser.js';
5
+ import { dump } from './dump.js';
6
+
7
+ export async function transform(options) {
8
+ const now = Date.now();
9
+ const configurations = await load(options);
10
+ for(const config of configurations)
11
+ await task(config);
12
+ console.info(`Transformed in ${Date.now() - now}ms`);
13
+ }
14
+
15
+ async function task({files, dest, cwd, type, space}) {
16
+ console.info('Transform task config:', {files, dest, cwd, type, space});
17
+ const m = new Map();
18
+ for(const file of files) {
19
+ const dir = path.resolve(dest, path.dirname(file));
20
+ for(const {name, data} of (await prepare(path.resolve(cwd, file)))) {
21
+ if(name[0] === "#") continue;
22
+ let sheet = path.resolve(dir, name.split('#')[0]);
23
+ if(sheet[0] === '>') sheet = sheet.substring(1)
24
+ sheet = sheet.replace('<arr>', '');
25
+ if(!m.has(sheet))
26
+ m.set(sheet, new JobData());
27
+ m.get(sheet).append(parser(data));
28
+ }
29
+ }
30
+ for(const [sheet, data] of m)
31
+ await dump(sheet, data.result(), type, space);
32
+ }
33
+
34
+ class JobData {
35
+ constructor(data) {
36
+ if(data) this.append(data);
37
+ }
38
+
39
+ #data = [];
40
+
41
+ append(data) {
42
+ this.#data.push(data);
43
+ }
44
+
45
+ result() {
46
+ if(!this.#data.length) return {};
47
+ const data = this.#data;
48
+ let result;
49
+ if(Array.isArray(data[0])) {
50
+ result = [];
51
+ for(const subs of data)
52
+ result.push(...Object.values(subs));
53
+ } else {
54
+ result = {};
55
+ for(const subs of data)
56
+ Object.assign(result, subs);
57
+ }
58
+ return result;
59
+ }
60
+ }
package/src/io.js DELETED
@@ -1,127 +0,0 @@
1
- import { readFile, writeFile, stat, readdir } from 'fs/promises';
2
- import * as XLSX from 'xlsx';
3
- import { join, extname, dirname, resolve } from 'path';
4
- import yaml from 'js-yaml';
5
-
6
- function stringify(data, space) {
7
- return JSON.stringify(data, null, space);
8
- }
9
-
10
- function cjs(data, space) {
11
- return `module.exports = ${stringify(data, space)}`;
12
- }
13
-
14
- function esm(data, space) {
15
- return `export default ${stringify(data, space)}`;
16
- }
17
-
18
- function yamlify(data, space) {
19
- return yaml.dump(data, {
20
- indent: space || undefined,
21
- });
22
- }
23
-
24
- export async function read(xlsxPath) {
25
- const xlsxFileBuffer = await readFile(xlsxPath);
26
- const xlsx = XLSX.read(xlsxFileBuffer, {type: 'buffer'});
27
- const sheets = xlsx.Sheets;
28
- const data = {};
29
- for(const sheetName in sheets) {
30
- const sheetRawData = sheets[sheetName];
31
- if(!sheetRawData['!ref']) break;
32
- data[sheetName] = XLSX.utils.sheet_to_json(sheetRawData, { header: 1 });
33
- }
34
- return data;
35
- }
36
-
37
- export function getWrite(type, space) {
38
- let format, extname;
39
- switch(type) {
40
- case 'commonjs':
41
- case 'cjs':
42
- extname = '.cjs';
43
- format = cjs; break;
44
- case 'javascript':
45
- case 'js':
46
- extname = '.js';
47
- format = esm; break;
48
- case 'esm':
49
- case 'mjs':
50
- extname = '.mjs';
51
- format = esm; break;
52
- case 'yml':
53
- case 'yaml':
54
- extname = '.yaml';
55
- format = yamlify; break;
56
- case 'json':
57
- default:
58
- extname = '.json';
59
- format = stringify; break;
60
- }
61
- return (data, target, basename) => writeFile(
62
- join(target, `${basename}${extname}`),
63
- format(data, Number(space)||0)
64
- );
65
- }
66
-
67
- async function walk(filePath) {
68
- const xlsxPaths = [];
69
- if(Array.isArray(filePath)) {
70
- for(const subPath of filePath)
71
- xlsxPaths.push(await walk(subPath));
72
- return xlsxPaths.flat();
73
- }
74
- const fileStat = await stat(filePath);
75
- if(!fileStat.isDirectory()) {
76
- const ext = extname(filePath);
77
- if( ext=='.xls' || ext=='.xlsx' ) xlsxPaths.push(filePath);
78
- return xlsxPaths;
79
- }
80
-
81
- const dirData = await readdir(filePath);
82
- for(const subPath of dirData)
83
- xlsxPaths.push(await walk(join(filePath, subPath)));
84
- return xlsxPaths.flat();
85
- }
86
-
87
- async function req(config) {
88
- const { configurations } = JSON.parse(await readFile(config));
89
- const jobs = [];
90
- const dir = dirname(config);
91
- for(const { source, target } of configurations) {
92
- const job = {};
93
- if(Array.isArray(source)) {
94
- job.source = [];
95
- for(const p of source)
96
- job.source.push(await walk(resolve(dir, p)))
97
- job.source = job.source.flat();
98
- } else {
99
- job.source = await walk(resolve(dir, source));
100
- }
101
- job.target = resolve(dir, target);
102
- jobs.push(job);
103
- }
104
- return jobs;
105
- }
106
-
107
- export async function jobs(configs) {
108
- const list = [];
109
- const files = [];
110
- for(const config of configs) {
111
- switch(extname(config)) {
112
- case '.json':
113
- const jobs = await req(config);
114
- if(jobs) list.push(jobs);
115
- break;
116
- default:
117
- files.push(config);
118
- break;
119
- }
120
- }
121
- if(files.length > 0) {
122
- const source = await walk(files);
123
- const target = dirname(source[0]);
124
- list.push({ source, target });
125
- }
126
- return list.flat();
127
- }
@@ -1,67 +0,0 @@
1
- import { parser } from './parser.js';
2
- import { merge } from './merge.js';
3
-
4
- export async function jobs(jobs, r, w) {
5
- for(const { source, target } of jobs)
6
- await job(source, target, r, w);
7
- }
8
-
9
- export async function job(source, target, r, w) {
10
- const merges = {};
11
- for(const xlsxPath of source) {
12
- const rawData = await r(xlsxPath);
13
- const { merge: mergeData, write } = transform(rawData);
14
- if(write) {
15
- for(const sheetName in write) {
16
- w(write[sheetName], target, sheetName);
17
- }
18
- }
19
-
20
- if(mergeData) {
21
- for(const sheetName in mergeData) {
22
- const [a, b] = sheetName.split('.');
23
- if(b) {
24
- const data = {[b]: mergeData[sheetName]}
25
- if(!merges[a]) {
26
- merges[a] = [ data ];
27
- } else {
28
- merges[a].push(data);
29
- }
30
- continue;
31
- }
32
- if(!merges[sheetName]) {
33
- merges[sheetName] = [ mergeData[sheetName] ];
34
- } else {
35
- merges[sheetName].push(mergeData[sheetName]);
36
- }
37
- }
38
-
39
- }
40
- }
41
-
42
- for(const sheetName in merges) {
43
- const data = merge(merges[sheetName]);
44
- w(data, target, sheetName);
45
- }
46
- }
47
-
48
- export function transform(rawSheetsData) {
49
- const merge = {};
50
- const write = {};
51
- for(const rawSheetName in rawSheetsData) {
52
- const rawData = rawSheetsData[rawSheetName];
53
- if(rawSheetName[0] === "#") continue;
54
- let sheetName = rawSheetName;
55
- const isArray = rawSheetName.substring(
56
- rawSheetName.length - 5,
57
- rawSheetName.length
58
- ) === "<arr>";
59
- if(isArray) sheetName = sheetName.substring(0, sheetName.length - 5);
60
- const isMerge = rawSheetName[0] === ">";
61
- if(isMerge) sheetName = sheetName.substring(1);
62
- const data = parser(rawData, isArray);
63
- if(isMerge) merge[sheetName] = data;
64
- else write[sheetName] = data;
65
- }
66
- return { merge, write };
67
- }
@@ -1,6 +0,0 @@
1
- export function merge(datas) {
2
- if(Array.isArray(datas[0]))
3
- return datas.flat();
4
-
5
- return Object.assign({}, ...datas);
6
- }