pake-cli 0.0.1-beta.9 → 0.0.1

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.
Files changed (90) hide show
  1. package/.ecrc.json +3 -0
  2. package/.editorconfig +24 -0
  3. package/.github/FUNDING.yml +2 -2
  4. package/.github/ISSUE_TEMPLATE/bug.md +13 -0
  5. package/.github/workflows/editorconfig-check.yml +23 -0
  6. package/.github/workflows/main.yml +17 -0
  7. package/.github/workflows/rust-code-quality-check.yml +89 -0
  8. package/.prettierignore +4 -0
  9. package/.vscode/settings.json +1 -0
  10. package/CODE_OF_CONDUCT.md +128 -0
  11. package/CONTRIBUTING.md +26 -0
  12. package/LICENSE +21 -0
  13. package/README.md +175 -54
  14. package/README_EN.md +91 -53
  15. package/app.csv +9 -0
  16. package/bin/README.md +72 -0
  17. package/bin/builders/MacBuilder.ts +13 -14
  18. package/bin/builders/base.ts +10 -1
  19. package/bin/builders/common.ts +9 -4
  20. package/bin/cli.ts +12 -5
  21. package/bin/defaults.ts +1 -0
  22. package/bin/options/icon.ts +51 -53
  23. package/bin/options/index.ts +3 -5
  24. package/bin/types.ts +3 -3
  25. package/bin/utils/shell.ts +1 -0
  26. package/bin/utils/tlds.ts +1489 -0
  27. package/bin/utils/url.ts +26 -0
  28. package/dist/cli.js +1620 -101
  29. package/dist/twitter.css +176 -0
  30. package/icns2png.py +38 -0
  31. package/package.json +8 -7
  32. package/pake-default.icns +0 -0
  33. package/rollup.config.js +1 -1
  34. package/script/build.bat +80 -0
  35. package/script/build.sh +122 -0
  36. package/script/sd-apple-x64 +0 -0
  37. package/script/sd-linux-x64 +0 -0
  38. package/script/sd.exe +0 -0
  39. package/src-tauri/Cargo.lock +344 -65
  40. package/src-tauri/Cargo.toml +14 -6
  41. package/src-tauri/assets/com-tw93-weread.desktop +10 -0
  42. package/src-tauri/build.rs +1 -1
  43. package/src-tauri/icons/icon.icns +0 -0
  44. package/src-tauri/icons/reference.icns +0 -0
  45. package/src-tauri/icons/translate.icns +0 -0
  46. package/src-tauri/icons/twitter.icns +0 -0
  47. package/src-tauri/icons/{weRead.icns → weread.icns} +0 -0
  48. package/src-tauri/icons/youtube.icns +0 -0
  49. package/src-tauri/png/code_256.ico +0 -0
  50. package/src-tauri/png/code_32.ico +0 -0
  51. package/src-tauri/png/code_512.png +0 -0
  52. package/src-tauri/png/flomo_256.ico +0 -0
  53. package/src-tauri/png/flomo_32.ico +0 -0
  54. package/src-tauri/png/flomo_512.png +0 -0
  55. package/src-tauri/png/reference_256.ico +0 -0
  56. package/src-tauri/png/reference_32.ico +0 -0
  57. package/src-tauri/png/reference_512.png +0 -0
  58. package/src-tauri/png/tool_256.ico +0 -0
  59. package/src-tauri/png/tool_32.ico +0 -0
  60. package/src-tauri/png/tool_512.png +0 -0
  61. package/src-tauri/png/translate_256.ico +0 -0
  62. package/src-tauri/png/translate_32.ico +0 -0
  63. package/src-tauri/png/translate_512.png +0 -0
  64. package/src-tauri/png/twitter_256.ico +0 -0
  65. package/src-tauri/png/twitter_32.ico +0 -0
  66. package/src-tauri/png/twitter_512.png +0 -0
  67. package/src-tauri/png/weread_256.ico +0 -0
  68. package/src-tauri/png/weread_32.ico +0 -0
  69. package/src-tauri/png/weread_512.png +0 -0
  70. package/src-tauri/png/witeboard_256.ico +0 -0
  71. package/src-tauri/png/witeboard_32.ico +0 -0
  72. package/src-tauri/png/witeboard_512.png +0 -0
  73. package/src-tauri/png/youtube_256.ico +0 -0
  74. package/src-tauri/png/youtube_32.ico +0 -0
  75. package/src-tauri/png/youtube_512.png +0 -0
  76. package/src-tauri/png/yuque_256.ico +0 -0
  77. package/src-tauri/png/yuque_32.ico +0 -0
  78. package/src-tauri/png/yuque_512.png +0 -0
  79. package/src-tauri/src/main.rs +130 -25
  80. package/src-tauri/src/pake.js +140 -77
  81. package/src-tauri/tauri.conf.json +30 -13
  82. package/bin/options/title.ts +0 -14
  83. package/src-tauri/icons/anymind.icns +0 -0
  84. package/src-tauri/icons/fanfou.icns +0 -0
  85. package/src-tauri/icons/fone.icns +0 -0
  86. package/src-tauri/icons/jdread.icns +0 -0
  87. package/src-tauri/icons/jike.icns +0 -0
  88. package/src-tauri/icons/roam.icns +0 -0
  89. package/src-tauri/icons/vercel.icns +0 -0
  90. package/src-tauri/icons/whatsapp.icns +0 -0
@@ -4,19 +4,17 @@ import prompts from 'prompts';
4
4
  import { checkRustInstalled, installRust } from '@/helpers/rust.js';
5
5
  import { PakeAppOptions } from '@/types.js';
6
6
  import { IBuilder } from './base.js';
7
- import appRootPath from 'app-root-path';
8
7
  import { shellExec } from '@/utils/shell.js';
9
8
  import tauriConf from '../../src-tauri/tauri.conf.json';
10
- import { dir } from 'tmp-promise';
9
+ import { fileURLToPath } from 'url';
10
+ import log from 'loglevel';
11
11
 
12
12
  export default class MacBuilder implements IBuilder {
13
13
  async prepare() {
14
14
  if (checkRustInstalled()) {
15
- console.log('Rust has been installed');
16
15
  return;
17
16
  }
18
17
 
19
- console.warn('Rust is not installed, show prompt');
20
18
  const res = await prompts({
21
19
  type: 'confirm',
22
20
  message: 'Detect you have not installed Rust, install it now?',
@@ -27,40 +25,41 @@ export default class MacBuilder implements IBuilder {
27
25
  // TODO 国内有可能会超时
28
26
  await installRust();
29
27
  } else {
30
- console.error('Error: Pake need Rust to package your webapp!!!');
28
+ log.error('Error: Pake need Rust to package your webapp!!!');
31
29
  process.exit(2);
32
30
  }
33
31
  }
34
32
 
35
33
  async build(url: string, options: PakeAppOptions) {
36
- console.log('PakeAppOptions', options);
34
+ log.debug('PakeAppOptions', options);
37
35
 
38
- const { width, height, fullscreen, transparent, title, resizable, identifier, name } = options;
36
+ const { width, height, fullscreen, transparent, resizable, identifier, name } = options;
39
37
 
40
38
  const tauriConfWindowOptions = {
41
39
  width,
42
40
  height,
43
41
  fullscreen,
44
42
  transparent,
45
- title,
46
43
  resizable,
47
44
  };
48
45
 
46
+ // TODO 下面这块逻辑还可以再拆 目前比较简单
49
47
  Object.assign(tauriConf.tauri.windows[0], { url, ...tauriConfWindowOptions });
50
48
  tauriConf.package.productName = name;
51
49
  tauriConf.tauri.bundle.identifier = identifier;
52
50
  tauriConf.tauri.bundle.icon = [options.icon];
53
51
 
54
- const { path: dirPath } = await dir();
55
- const configJsonPath = `${dirPath}/config.json`;
52
+ const npmDirectory = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
53
+ const configJsonPath = path.join(npmDirectory, 'src-tauri/tauri.conf.json');
56
54
  await fs.writeFile(configJsonPath, Buffer.from(JSON.stringify(tauriConf), 'utf-8'));
57
55
 
58
- const code = await shellExec(`npx tauri build --config ${configJsonPath} --target universal-apple-darwin`);
56
+ const code = await shellExec(`cd ${npmDirectory} && npm run build`);
59
57
  const dmgName = `${name}_${'0.2.0'}_universal.dmg`;
60
- await fs.copyFile(this.getBuildedAppPath(dmgName), path.resolve(dmgName));
58
+ const appPath = this.getBuildedAppPath(npmDirectory, dmgName);
59
+ await fs.copyFile(appPath, path.resolve(`${name}_universal.dmg`));
61
60
  }
62
61
 
63
- getBuildedAppPath(dmgName: string) {
64
- return path.join(appRootPath.path, 'src-tauri/target/universal-apple-darwin/release/bundle/dmg', dmgName);
62
+ getBuildedAppPath(npmDirectory: string, dmgName: string) {
63
+ return path.join(npmDirectory, 'src-tauri/target/universal-apple-darwin/release/bundle/dmg', dmgName);
65
64
  }
66
65
  }
@@ -1,7 +1,16 @@
1
1
  import { PakeAppOptions } from '@/types.js';
2
2
 
3
+ /**
4
+ * Builder接口
5
+ * 不同平台打包过程需要实现 prepare 和 build 方法
6
+ */
3
7
  export interface IBuilder {
8
+ /** 前置检查 */
4
9
  prepare(): Promise<void>;
10
+ /**
11
+ * 开始打包
12
+ * @param url 打包url
13
+ * @param options 配置参数
14
+ */
5
15
  build(url: string, options: PakeAppOptions): Promise<void>;
6
- // getIcon(icon?: string): Promise<string>;
7
16
  }
@@ -1,6 +1,11 @@
1
- import path from 'path';
2
- import appRootPath from 'app-root-path';
1
+ import prompts from 'prompts';
3
2
 
4
- export function getBuildedAppPath(name: string, version: string) {
5
- return path.join(appRootPath.path, 'src-tauri/target/universal-apple-darwin/release/bundle/dmg', `${name}_${version}_universal.dmg`);
3
+ export async function promptText(message: string, initial?: string) {
4
+ const response = await prompts({
5
+ type: 'text',
6
+ name: 'content',
7
+ message,
8
+ initial,
9
+ });
10
+ return response.content;
6
11
  }
package/bin/cli.ts CHANGED
@@ -4,20 +4,27 @@ import { PakeCliOptions } from './types.js';
4
4
  import { validateNumberInput, validateUrlInput } from './utils/validate.js';
5
5
  import handleInputOptions from './options/index.js';
6
6
  import BuilderFactory from './builders/BuilderFactory.js';
7
+ import log from 'loglevel';
7
8
 
8
- program.version('0.0.1').description('A cli application can build app from website, driven by tauri');
9
+ program.version('0.0.1').description('A cli application can package a web page to desktop application');
9
10
 
10
11
  program
12
+ .showHelpAfterError()
11
13
  .argument('<url>', 'the web url you want to package', validateUrlInput)
12
14
  .option('--name <string>', 'application name')
13
- .option('--title <string>', 'application window title')
14
15
  .option('--icon <string>', 'application icon', DEFAULT_PAKE_OPTIONS.icon)
15
- .option('--height <number>', 'application window height', validateNumberInput, DEFAULT_PAKE_OPTIONS.height)
16
- .option('--width <number>', 'application window width', validateNumberInput, DEFAULT_PAKE_OPTIONS.width)
17
- .option('--no-resizable', 'whether the application window can be resizable', DEFAULT_PAKE_OPTIONS.resizable)
16
+ .option('--height <number>', 'window height', validateNumberInput, DEFAULT_PAKE_OPTIONS.height)
17
+ .option('--width <number>', 'window width', validateNumberInput, DEFAULT_PAKE_OPTIONS.width)
18
+ .option('--no-resizable', 'whether the window can be resizable', DEFAULT_PAKE_OPTIONS.resizable)
18
19
  .option('--fullscreen', 'makes the packaged app start in full screen', DEFAULT_PAKE_OPTIONS.fullscreen)
19
20
  .option('--transparent', 'transparent title bar', DEFAULT_PAKE_OPTIONS.transparent)
21
+ .option('--debug', 'debug', DEFAULT_PAKE_OPTIONS.transparent)
20
22
  .action(async (url: string, options: PakeCliOptions) => {
23
+ log.setDefaultLevel('info')
24
+ if (options.debug) {
25
+ log.setLevel('debug');
26
+ }
27
+
21
28
  const builder = BuilderFactory.create();
22
29
  await builder.prepare();
23
30
 
package/bin/defaults.ts CHANGED
@@ -7,6 +7,7 @@ export const DEFAULT_PAKE_OPTIONS: PakeCliOptions = {
7
7
  fullscreen: false,
8
8
  resizable: true,
9
9
  transparent: false,
10
+ debug: false,
10
11
  };
11
12
 
12
13
  export const DEFAULT_APP_NAME = 'Pake';
@@ -1,18 +1,16 @@
1
- import axios from 'axios';
2
- import { fileTypeFromBuffer } from 'file-type';
3
- import url from 'url';
4
- import { PakeAppOptions } from '../types.js';
5
- import { dir, file } from 'tmp-promise';
6
- import path from 'path';
7
- import pageIcon from 'page-icon';
8
- import png2icons from 'png2icons';
9
- import ICO from 'icojs';
10
- import fs from 'fs/promises';
1
+ import axios from "axios";
2
+ import { fileTypeFromBuffer } from "file-type";
3
+ import { PakeAppOptions } from "../types.js";
4
+ import { dir } from "tmp-promise";
5
+ import path from "path";
6
+ import fs from "fs/promises";
7
+ import { fileURLToPath } from "url";
8
+ import log from "loglevel";
11
9
 
12
10
  export async function handleIcon(options: PakeAppOptions, url: string) {
13
- console.log(options.icon);
14
11
  if (options.icon) {
15
- if (options.icon.startsWith('http')) {
12
+ if (options.icon.startsWith("http")) {
13
+ log.info(options.icon);
16
14
  return downloadIcon(options.icon);
17
15
  } else {
18
16
  return path.resolve(options.icon);
@@ -24,58 +22,58 @@ export async function handleIcon(options: PakeAppOptions, url: string) {
24
22
  }
25
23
 
26
24
  export async function inferIcon(name: string, url: string) {
27
- let icon = await getIconFromMacosIcons(name);
28
- if (!icon) {
29
- icon = await getIconFromPageUrl(url);
30
- }
31
- if (!icon) {
32
- // TODO default icon
33
- }
34
- return icon;
25
+ log.info(
26
+ "You have not provided an app icon, use the default icon(can use --icon option to assign an icon)"
27
+ );
28
+ const npmDirectory = path.join(
29
+ path.dirname(fileURLToPath(import.meta.url)),
30
+ ".."
31
+ );
32
+ return path.join(npmDirectory, "pake-default.icns");
35
33
  }
36
34
 
37
- export async function getIconFromPageUrl(url: string) {
38
- const icon = await pageIcon(url);
39
- console.log(icon);
40
- if (icon.ext === '.ico') {
41
- const a = await ICO.parse(icon.data);
42
- icon.data = Buffer.from(a[0].buffer);
43
- }
35
+ // export async function getIconFromPageUrl(url: string) {
36
+ // const icon = await pageIcon(url);
37
+ // console.log(icon);
38
+ // if (icon.ext === '.ico') {
39
+ // const a = await ICO.parse(icon.data);
40
+ // icon.data = Buffer.from(a[0].buffer);
41
+ // }
44
42
 
45
- const iconDir = (await dir()).path;
46
- const iconPath = path.join(iconDir, `/icon.icns`);
43
+ // const iconDir = (await dir()).path;
44
+ // const iconPath = path.join(iconDir, `/icon.icns`);
47
45
 
48
- const out = png2icons.createICNS(icon.data, png2icons.BILINEAR, 0);
46
+ // const out = png2icons.createICNS(icon.data, png2icons.BILINEAR, 0);
49
47
 
50
- await fs.writeFile(iconPath, out);
51
- return iconPath;
52
- }
48
+ // await fs.writeFile(iconPath, out);
49
+ // return iconPath;
50
+ // }
53
51
 
54
- export async function getIconFromMacosIcons(name: string) {
55
- const data = {
56
- query: name,
57
- filters: 'approved:true',
58
- hitsPerPage: 10,
59
- page: 1,
60
- };
61
- const res = await axios.post('https://p1txh7zfb3-2.algolianet.com/1/indexes/macOSicons/query?x-algolia-agent=Algolia%20for%20JavaScript%20(4.13.1)%3B%20Browser', data, {
62
- headers: {
63
- 'x-algolia-api-key': '0ba04276e457028f3e11e38696eab32c',
64
- 'x-algolia-application-id': 'P1TXH7ZFB3',
65
- },
66
- });
67
- if (!res.data.hits.length) {
68
- return '';
69
- } else {
70
- return downloadIcon(res.data.hits[0].icnsUrl);
71
- }
72
- }
52
+ // export async function getIconFromMacosIcons(name: string) {
53
+ // const data = {
54
+ // query: name,
55
+ // filters: 'approved:true',
56
+ // hitsPerPage: 10,
57
+ // page: 1,
58
+ // };
59
+ // const res = await axios.post('https://p1txh7zfb3-2.algolianet.com/1/indexes/macOSicons/query?x-algolia-agent=Algolia%20for%20JavaScript%20(4.13.1)%3B%20Browser', data, {
60
+ // headers: {
61
+ // 'x-algolia-api-key': '0ba04276e457028f3e11e38696eab32c',
62
+ // 'x-algolia-application-id': 'P1TXH7ZFB3',
63
+ // },
64
+ // });
65
+ // if (!res.data.hits.length) {
66
+ // return '';
67
+ // } else {
68
+ // return downloadIcon(res.data.hits[0].icnsUrl);
69
+ // }
70
+ // }
73
71
 
74
72
  export async function downloadIcon(iconUrl: string) {
75
73
  let iconResponse;
76
74
  try {
77
75
  iconResponse = await axios.get(iconUrl, {
78
- responseType: 'arraybuffer',
76
+ responseType: "arraybuffer",
79
77
  });
80
78
  } catch (error) {
81
79
  if (error.response && error.response.status === 404) {
@@ -1,19 +1,17 @@
1
+ import { promptText } from '@/builders/common.js';
2
+ import { getDomain } from '@/utils/url.js';
1
3
  import { getIdentifier } from '../helpers/tauriConfig.js';
2
4
  import { PakeAppOptions, PakeCliOptions } from '../types.js';
3
5
  import { handleIcon } from './icon.js';
4
- import { getTitleByURL } from './title.js';
5
6
 
6
7
  export default async function handleOptions(options: PakeCliOptions, url: string): Promise<PakeAppOptions> {
7
8
  const appOptions: PakeAppOptions = {
8
9
  ...options,
9
10
  identifier: '',
10
11
  };
11
- if (!appOptions.title) {
12
- appOptions.title = await getTitleByURL(url);
13
- }
14
12
 
15
13
  if (!appOptions.name) {
16
- appOptions.name = appOptions.title;
14
+ appOptions.name = await promptText('please input your application name', getDomain(url));
17
15
  }
18
16
 
19
17
  appOptions.identifier = getIdentifier(appOptions.name, url);
package/bin/types.ts CHANGED
@@ -2,9 +2,6 @@ export interface PakeCliOptions {
2
2
  /** 应用名称 */
3
3
  name?: string;
4
4
 
5
- /** 不填会取 url 的 title,取不到默认 webapp */
6
- title?: string;
7
-
8
5
  /** 应用icon */
9
6
  icon: string;
10
7
 
@@ -22,6 +19,9 @@ export interface PakeCliOptions {
22
19
 
23
20
  /** 是否开启沉浸式头部,默认为 false 不开启 ƒ*/
24
21
  transparent: boolean;
22
+
23
+ /** 调试模式,会输出更多日志 */
24
+ debug: boolean;
25
25
  }
26
26
 
27
27
  export interface PakeAppOptions extends PakeCliOptions {
@@ -1,4 +1,5 @@
1
1
  import shelljs from 'shelljs';
2
+
2
3
  export function shellExec(command: string) {
3
4
  return new Promise<number>((resolve, reject) => {
4
5
  shelljs.exec(command, { async: true, silent: false}, (code) => {