Skip to content

Commit 4cd0393

Browse files
authored
Merge pull request #16 from mistlog/develop
release 0.2.1
2 parents 7f6b22f + eb116a1 commit 4cd0393

File tree

7 files changed

+254
-72
lines changed

7 files changed

+254
-72
lines changed

cli/cli.ts

+63-54
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,75 @@
11
#!/usr/bin/env node
22
import * as program from "commander";
3-
import {
4-
ComposeFile,
5-
ComposeDirectory,
6-
InspectDirectory,
7-
InspectFile,
8-
CrossoutDirectory,
9-
ISvelteDraftConfig,
10-
} from "./literator";
11-
import { resolve } from "path";
12-
import { lstatSync } from "fs";
13-
import { readJSONSync } from "fs-extra";
3+
import { ComposeDirectory, CrossoutDirectory } from "./literator";
4+
import { resolve, basename, join } from "path";
5+
import { lstatSync, readJSONSync, copySync, emptyDirSync } from "fs-extra";
146

15-
import { cosmiconfig } from "cosmiconfig";
16-
import { default as tsLoader } from "@endemolshinegroup/cosmiconfig-typescript-loader";
7+
import { addSvelteExtension } from "./fix";
8+
import { generateType } from "./type";
9+
import { withConfig } from "./config";
1710

18-
const package_json = readJSONSync(resolve(__dirname, "../../package.json"));
19-
program.version(package_json.version);
20-
program.option("-w, --watch", "compose file or files in directory in watch mode");
21-
program.option("-clean, --clean", "remove generated files");
22-
program.parse(process.argv);
11+
const packageJSON = readJSONSync(resolve(__dirname, "../../package.json"));
12+
program.version(packageJSON.version);
2313

24-
const args = program.args;
14+
//
15+
program
16+
.command("build")
17+
.description("build component and script")
18+
.action(() => {
19+
withConfig(config => {
20+
const { include, outDir } = config;
21+
const workingDirectory = process.cwd();
2522

26-
if (args.length === 0) {
27-
program.help();
28-
} else {
29-
const [target] = args;
23+
include.forEach(inDir => {
24+
const path = resolve(workingDirectory, inDir);
25+
if (lstatSync(path).isDirectory()) {
26+
ComposeDirectory(path, config, () => {
27+
const newOutDir = join(outDir, basename(inDir));
28+
emptyDirSync(newOutDir);
29+
copySync(inDir, newOutDir, {
30+
filter: (src, dest) => {
31+
if (
32+
basename(src).endsWith(".tsx") ||
33+
basename(src).endsWith(".ts")
34+
) {
35+
return false;
36+
}
3037

31-
if (target) {
32-
if (program.clean) {
33-
CrossoutDirectory(target);
34-
} else {
35-
Transcribe(target);
36-
}
37-
}
38-
}
38+
return true;
39+
},
40+
});
41+
addSvelteExtension(newOutDir);
42+
});
43+
}
44+
});
3945

40-
function Transcribe(target: string) {
41-
//
42-
// find config
43-
const explorer = cosmiconfig("svelte-draft", {
44-
searchPlaces: [`svelte-draft.config.ts`],
45-
loaders: {
46-
".ts": tsLoader,
47-
},
46+
generateType(include, outDir);
47+
});
4848
});
49-
50-
explorer.search().then(config_info => {
51-
let config: ISvelteDraftConfig = { DSLs: [] };
52-
if (config_info && !config_info.isEmpty) {
53-
config = { ...config, ...config_info.config };
54-
}
55-
56-
//
57-
const working_directory = process.cwd();
58-
const path = resolve(working_directory, target);
59-
49+
//
50+
program
51+
.command("transcribe <dir>")
52+
.description("generate component and script")
53+
.action(dir => {
54+
withConfig(config => {
55+
const path = resolve(process.cwd(), dir);
56+
if (lstatSync(path).isDirectory()) {
57+
ComposeDirectory(path, config, () => {
58+
addSvelteExtension(path);
59+
});
60+
}
61+
});
62+
});
63+
//
64+
program
65+
.command("clean <dir>")
66+
.description("remove generated files")
67+
.action(dir => {
68+
const path = resolve(process.cwd(), dir);
6069
if (lstatSync(path).isDirectory()) {
61-
program.watch ? InspectDirectory(path, config) : ComposeDirectory(path, config);
62-
} else {
63-
program.watch ? InspectFile(path, config) : ComposeFile(path, config);
70+
CrossoutDirectory(path);
6471
}
6572
});
66-
}
73+
74+
//
75+
program.parse(process.argv);

cli/config.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ISvelteDraftConfig } from "./literator";
2+
import { cosmiconfig } from "cosmiconfig";
3+
import { default as tsLoader } from "@endemolshinegroup/cosmiconfig-typescript-loader";
4+
5+
export function withConfig(callback: (config: ISvelteDraftConfig) => void) {
6+
const explorer = cosmiconfig("svelte-draft", {
7+
searchPlaces: [`svelte-draft.config.ts`],
8+
loaders: {
9+
".ts": tsLoader,
10+
},
11+
});
12+
13+
explorer.search().then(configInfo => {
14+
let config: ISvelteDraftConfig = { DSLs: [], include: [], outDir: "./build" };
15+
if (configInfo && !configInfo.isEmpty) {
16+
config = { ...config, ...configInfo.config };
17+
}
18+
callback(config);
19+
});
20+
}

cli/fix.ts

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
const svelte = require("svelte/compiler");
2+
const fs = require("fs");
3+
const { resolve } = require("path");
4+
const { transformSync } = require("@babel/core");
5+
const traverse = require("@babel/traverse").default;
6+
const generate = require("@babel/generator").default;
7+
const traverseDirectory = require("filewalker");
8+
9+
async function preprocessSvelte(path) {
10+
const source = fs.readFileSync(path, "utf8");
11+
const { code } = await svelte.preprocess(
12+
source,
13+
{
14+
script: ({ content, filename }) => {
15+
const code = preprocessImport(content, filename);
16+
return { code };
17+
},
18+
},
19+
{
20+
filename: path,
21+
}
22+
);
23+
24+
return code;
25+
}
26+
27+
/**
28+
* add .svelte in "import" if necessary
29+
*/
30+
function preprocessImport(content, filename) {
31+
const ast = transformSync(content, {
32+
filename,
33+
ast: true,
34+
}).ast;
35+
36+
traverse(ast, {
37+
ImportDeclaration(astPath) {
38+
const sourceName = astPath.node.source?.value;
39+
if (!sourceName) {
40+
return;
41+
}
42+
const importFrom = resolve(filename, "../", sourceName);
43+
const svelteFile = importFrom + ".svelte";
44+
if (fs.existsSync(svelteFile)) {
45+
astPath.node.source.value += ".svelte";
46+
}
47+
},
48+
});
49+
50+
const code = generate(ast).code;
51+
return code;
52+
}
53+
54+
function preprocessScript(content, filename) {
55+
const ast = transformSync(content, {
56+
filename,
57+
ast: true,
58+
}).ast;
59+
60+
traverse(ast, {
61+
ImportDeclaration(astPath) {
62+
const sourceName = astPath.node.source?.value;
63+
if (!sourceName) {
64+
return;
65+
}
66+
const importFrom = resolve(filename, "../", sourceName);
67+
const svelteFile = importFrom + ".svelte";
68+
if (fs.existsSync(svelteFile)) {
69+
astPath.node.source.value += ".svelte";
70+
}
71+
},
72+
ExportDeclaration(astPath) {
73+
const sourceName = astPath.node.source?.value;
74+
if (!sourceName) {
75+
return;
76+
}
77+
const importFrom = resolve(filename, "../", sourceName);
78+
const svelteFile = importFrom + ".svelte";
79+
if (fs.existsSync(svelteFile)) {
80+
astPath.node.source.value += ".svelte";
81+
}
82+
},
83+
});
84+
85+
const code = generate(ast).code;
86+
return code;
87+
}
88+
89+
export async function addSvelteExtension(path) {
90+
traverseDirectory(path)
91+
.on("file", async (relative, stats, absolute) => {
92+
if (absolute.endsWith(".svelte")) {
93+
const code = await preprocessSvelte(absolute);
94+
fs.writeFileSync(absolute, code, "utf8");
95+
} else if (absolute.endsWith(".js")) {
96+
const code = fs.readFileSync(absolute, "utf8");
97+
const withExtension = preprocessScript(code, absolute);
98+
fs.writeFileSync(absolute, withExtension, "utf8");
99+
}
100+
})
101+
.walk();
102+
}

cli/literator.ts

+28-12
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@ import * as TypescriptPreset from "@babel/preset-typescript";
1515

1616
export interface ISvelteDraftConfig {
1717
DSLs: Array<{ name: string; dsl: () => IDSL }>;
18+
include?: Array<string>;
19+
outDir?: string;
1820
}
1921

20-
function TraverseDirectory(path: string, callback: (name: string, path: string) => void) {
22+
function TraverseDirectory(
23+
path: string,
24+
callback: (name: string, path: string) => void,
25+
onTraverseEnd = () => {}
26+
) {
2127
const action = (relative: string, stats, absolute: string) => callback(relative, absolute);
22-
traverse(path).on("file", action).walk();
28+
traverse(path).on("file", action).on("done", onTraverseEnd).walk();
2329
}
2430

2531
export function InspectDirectory(path: string, config?: ISvelteDraftConfig) {
@@ -54,22 +60,32 @@ export function InspectFile(path: string, config?: ISvelteDraftConfig) {
5460
});
5561
}
5662

57-
export function ComposeDirectory(path: string, config?: ISvelteDraftConfig) {
58-
TraverseDirectory(path, (relative: string, absolute: string) => {
59-
if (absolute.endsWith(".tsx")) {
60-
try {
61-
ComposeFile(absolute, config);
62-
} catch (error) {
63-
console.log(`compose file failed: ${error.message}, source: ${relative}`);
63+
export function ComposeDirectory(
64+
path: string,
65+
config?: ISvelteDraftConfig,
66+
onTraverseEnd = () => {}
67+
) {
68+
TraverseDirectory(
69+
path,
70+
(relative: string, absolute: string) => {
71+
if (absolute.endsWith(".tsx") || absolute.endsWith(".ts")) {
72+
try {
73+
ComposeFile(absolute, config);
74+
} catch (error) {
75+
console.log(`compose file failed: ${error.message}, source: ${relative}`);
76+
}
6477
}
65-
}
66-
});
78+
},
79+
onTraverseEnd
80+
);
6781
}
6882

6983
export function CrossoutDirectory(path: string) {
7084
TraverseDirectory(path, (relative: string, absolute: string) => {
7185
if (absolute.endsWith(".tsx")) {
72-
removeSync(absolute.replace(".tsx", ""));
86+
removeSync(absolute.replace(".tsx", ".svelte"));
87+
} else if (absolute.endsWith(".ts")) {
88+
removeSync(absolute.replace(".ts", ".js"));
7389
}
7490
});
7591
}

cli/type.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { resolve } from "path";
2+
import { outputJSONSync, removeSync } from "fs-extra";
3+
import { exec } from "child_process";
4+
5+
export function generateType(include: Array<string>, outDir: string) {
6+
const workingDirectory = process.cwd();
7+
const typeConfigPath = resolve(__dirname, "temp.typeconfig.json");
8+
outputJSONSync(typeConfigPath, {
9+
compilerOptions: {
10+
target: "es6",
11+
module: "commonjs",
12+
moduleResolution: "node",
13+
jsx: "preserve",
14+
declaration: true,
15+
outDir: resolve(workingDirectory, outDir),
16+
emitDeclarationOnly: true,
17+
esModuleInterop: true,
18+
},
19+
include: include.map(each => resolve(workingDirectory, each)),
20+
});
21+
22+
exec(`npx tsc --project ${typeConfigPath}`, error => {
23+
// TODO: fix error report: [svelte] Cannot find module 'magic-string'
24+
// if (error) {
25+
// console.log(error);
26+
// }
27+
removeSync(typeConfigPath);
28+
});
29+
}

package-lock.json

+9-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)