From 95f1fc24a9b209560d1d71a70ca7716827a570cf Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 04:28:37 +0900 Subject: [PATCH 01/25] update no project root found message --- cli/init/index.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cli/init/index.ts b/cli/init/index.ts index 39173d30..1161898d 100644 --- a/cli/init/index.ts +++ b/cli/init/index.ts @@ -28,15 +28,16 @@ export async function init( } if (!baseproj) { - const { continue_witout_existing_project } = await prompt<{ - continue_witout_existing_project: boolean; + const { continue_with_new_project_using_template } = await prompt<{ + continue_with_new_project_using_template: boolean; }>({ name: "continue_witout_existing_project", + initial: true, type: "confirm", message: - "No project root is found (package.json or pubspec.yml) with framework configuration. Do you want to continue without creating a project?", + "No project is found (package.json or pubspec.yml) with framework configuration. Do you want to create new project with template?", }); - if (!continue_witout_existing_project) { + if (continue_with_new_project_using_template) { const _ = await init_base_project_with_template(cwd, { create_cwd_if_not_exists, }); From 59371904bc616498c4917c3c7a2252391c8ded31 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 04:55:00 +0900 Subject: [PATCH 02/25] add fpat prompt for `grida code` command --- cli/bin.ts | 14 ++-- cli/init/index.ts | 10 +++ cli/init/init-config-designsource-figma.ts | 78 ++++++++++++++++++++ cli/init/init-config-designsource.ts | 84 ++-------------------- 4 files changed, 102 insertions(+), 84 deletions(-) create mode 100644 cli/init/init-config-designsource-figma.ts diff --git a/cli/bin.ts b/cli/bin.ts index 15da436a..60e3944b 100644 --- a/cli/bin.ts +++ b/cli/bin.ts @@ -1,7 +1,7 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import { defaultConfigByFramework } from "@grida/builder-config-preset"; -import { init } from "./init"; +import { init, prompt_figma_personal_access_token } from "./init"; import { add } from "./add"; import { code } from "./code"; import { Framework } from "@grida/builder-platform-types"; @@ -11,6 +11,7 @@ import fs from "fs"; import { checkForUpdate } from "./update"; import { login, logout } from "./auth"; import { startFlutterDaemonServer } from "./flutter/daemon"; +import { parseFileId } from "@design-sdk/figma-url"; function loadenv(argv) { const { cwd } = argv; @@ -86,9 +87,13 @@ export default async function cli() { }, async ({ cwd, framework, uri, out, ...argv }) => { // - const _personal_access_token = argv[ - "figma-personal-access-token" - ] as string; + + const filekey = parseFileId(uri as string); + + // promp if not set + const _personal_access_token: string = + (argv["figma-personal-access-token"] as string) ?? + (await prompt_figma_personal_access_token(filekey)); // make this path absolute if relative path is given. const _outpath_abs: string = path.isAbsolute(out as string) @@ -98,6 +103,7 @@ export default async function cli() { const config_framework = defaultConfigByFramework( framework as Framework ); + if (!config_framework) { throw new Error(`Unknown framework: "${framework}"`); } diff --git a/cli/init/index.ts b/cli/init/index.ts index 1161898d..3d89ceda 100644 --- a/cli/init/index.ts +++ b/cli/init/index.ts @@ -284,3 +284,13 @@ function create_grida_fallback_dir( path: dir, }; } + +export * from "./init-.env"; +export * from "./init-.gitignore"; +export * from "./init-.grida"; +export * from "./init-base-project-with-teplate"; +export * from "./init-config-designsource"; +export * from "./init-config-designsource-figma"; +export * from "./init-grida.config.js"; +export * from "./init-package.json"; +export * from "./init-pubspec.yaml"; diff --git a/cli/init/init-config-designsource-figma.ts b/cli/init/init-config-designsource-figma.ts new file mode 100644 index 00000000..031865be --- /dev/null +++ b/cli/init/init-config-designsource-figma.ts @@ -0,0 +1,78 @@ +import { prompt } from "enquirer"; +import { parseFileId } from "@design-sdk/figma-url"; +import { + Client as FigmaApiClient, + User as FigmaUser, +} from "@design-sdk/figma-remote-api"; +import chalk from "chalk"; + +export async function prompt_figma_filekey() { + const { url } = await prompt<{ url: string }>({ + name: "url", + message: "Please enter your figma file url", + type: "input", + hint: "https://www.figma.com/file/xxxx", + required: true, + validate(value) { + if (!value) { + return "Please enter your figma file url. (copy & paste the link on the browser)"; + } + try { + const filekey = parseFileId(value); + if (!filekey) { + return false; + } + return true; + } catch (e) { + return e.message; + } + }, + }); + + const filekey = parseFileId(url); + return filekey; +} + +export async function prompt_figma_personal_access_token( + filekey: string +): Promise { + const _ = await prompt({ + name: "figma-personal-access-token", + message: "Please enter your figma personal access token.", + type: "password", + // @ts-ignore + async validate(value) { + // it's usually 43 chars long e.g "xxxxxx-xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx" + if (!value || value.length < 40 || value.trim().includes(" ")) { + return "Please enter your figma personal access token. How to 👉 https://grida.co/docs/with-figma/guides/how-to-get-personal-access-token"; + } + + const validationClient = FigmaApiClient({ + personalAccessToken: value, + }); + + let me: FigmaUser; + try { + me = (await validationClient.me()).data; + } catch (e) { + return "Invalid personal access token. Please try again."; + } + + try { + await validationClient.file(filekey, { + depth: 1, + }); + } catch (e) { + return `This token for user ${chalk.blue( + me.handle + )} has no access to file - ${chalk.blue( + `https://www.figma.com/file/${filekey}` + )} Make sure you are editor of the file.`; + } + + return true as boolean; + }, + }); + + return _["figma-personal-access-token"]; +} diff --git a/cli/init/init-config-designsource.ts b/cli/init/init-config-designsource.ts index 572f7a3a..4c0e0abf 100644 --- a/cli/init/init-config-designsource.ts +++ b/cli/init/init-config-designsource.ts @@ -1,14 +1,9 @@ import { prompt } from "enquirer"; -import { parseFileId } from "@design-sdk/figma-url"; -import type { - DesignSourceConfig, - FrameworkConfig, -} from "@grida/builder-config"; +import type { DesignSourceConfig } from "@grida/builder-config"; import { - Client as FigmaApiClient, - User as FigmaUser, -} from "@design-sdk/figma-remote-api"; -import chalk from "chalk"; + prompt_figma_filekey, + prompt_figma_personal_access_token, +} from "./init-config-designsource-figma"; export async function prompt_designsource_config(): Promise { const { provider } = await prompt<{ @@ -38,74 +33,3 @@ export async function prompt_designsource_config(): Promise } } } - -async function prompt_figma_filekey() { - const { url } = await prompt<{ url: string }>({ - name: "url", - message: "Please enter your figma file url", - type: "input", - hint: "https://www.figma.com/file/xxxx", - required: true, - validate(value) { - if (!value) { - return "Please enter your figma file url. (copy & paste the link on the browser)"; - } - try { - const filekey = parseFileId(value); - if (!filekey) { - return false; - } - return true; - } catch (e) { - return e.message; - } - }, - }); - - const filekey = parseFileId(url); - return filekey; -} - -async function prompt_figma_personal_access_token( - filekey: string -): Promise { - const _ = await prompt({ - name: "figma-personal-access-token", - message: "Please enter your figma personal access token.", - type: "password", - // @ts-ignore - async validate(value) { - // it's usually 43 chars long e.g "xxxxxx-xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx" - if (!value || value.length < 40 || value.trim().includes(" ")) { - return "Please enter your figma personal access token. How to 👉 https://grida.co/docs/with-figma/guides/how-to-get-personal-access-token"; - } - - const validationClient = FigmaApiClient({ - personalAccessToken: value, - }); - - let me: FigmaUser; - try { - me = (await validationClient.me()).data; - } catch (e) { - return "Invalid personal access token. Please try again."; - } - - try { - await validationClient.file(filekey, { - depth: 1, - }); - } catch (e) { - return `This token for user ${chalk.blue( - me.handle - )} has no access to file - ${chalk.blue( - `https://www.figma.com/file/${filekey}` - )} Make sure you are editor of the file.`; - } - - return true as boolean; - }, - }); - - return _["figma-personal-access-token"]; -} From fb7585fb8f985afd72ff2bb96f65320a9019ba90 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 05:34:28 +0900 Subject: [PATCH 03/25] update init proc --- cli/init/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cli/init/index.ts b/cli/init/index.ts index 3d89ceda..988d3a07 100644 --- a/cli/init/index.ts +++ b/cli/init/index.ts @@ -31,7 +31,7 @@ export async function init( const { continue_with_new_project_using_template } = await prompt<{ continue_with_new_project_using_template: boolean; }>({ - name: "continue_witout_existing_project", + name: "continue_with_new_project_using_template", initial: true, type: "confirm", message: @@ -42,6 +42,9 @@ export async function init( create_cwd_if_not_exists, }); if (_ == "exit") { + console.log( + "Cancelled. You can run `grida init` again after creating a project." + ); exit(0); } else { const { created, cwd: newcwd, name } = _; From e1bb7c33245043f370f0fd4dece8c41b8af2e275 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 05:45:51 +0900 Subject: [PATCH 04/25] add framework prompt for `grida code x` command --- cli/bin.ts | 14 ++-- cli/init/index.ts | 116 +---------------------------- cli/init/init-config-framework.ts | 119 ++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 119 deletions(-) create mode 100644 cli/init/init-config-framework.ts diff --git a/cli/bin.ts b/cli/bin.ts index 60e3944b..5c3a2ea9 100644 --- a/cli/bin.ts +++ b/cli/bin.ts @@ -1,7 +1,11 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import { defaultConfigByFramework } from "@grida/builder-config-preset"; -import { init, prompt_figma_personal_access_token } from "./init"; +import { + init, + prompt_figma_personal_access_token, + prompt_framework_config, +} from "./init"; import { add } from "./add"; import { code } from "./code"; import { Framework } from "@grida/builder-platform-types"; @@ -80,7 +84,7 @@ export default async function cli() { [loadenv] ) .command( - "code ", + "code [framework] ", "generate code from input uri", (argv) => { // return; @@ -100,9 +104,9 @@ export default async function cli() { ? (out as string) : path.resolve(cwd, out as string); - const config_framework = defaultConfigByFramework( - framework as Framework - ); + const config_framework = framework + ? defaultConfigByFramework(framework as Framework) + : await prompt_framework_config(cwd, undefined, false); if (!config_framework) { throw new Error(`Unknown framework: "${framework}"`); diff --git a/cli/init/index.ts b/cli/init/index.ts index 988d3a07..e4ace97b 100644 --- a/cli/init/index.ts +++ b/cli/init/index.ts @@ -16,6 +16,7 @@ import { init_base_project_with_template } from "./init-base-project-with-teplat import { create_grida_config_js } from "./init-grida.config.js"; import { init_dotgrida } from "./init-.grida"; import { init_gitignore } from "./init-.gitignore"; +import { prompt_framework_config } from "./init-config-framework"; export async function init( cwd = process.cwd(), @@ -126,120 +127,6 @@ const framework_gitignore_templates = { "react-native": "react-native", } as const; -async function prompt_framework_config( - cwd, - baseproj?: BaseProjectInfo | undefined, - initialized_with_template?: boolean -): Promise { - let framework: BaseProjectInfo["framework"] = baseproj?.framework; - if (!initialized_with_template) { - if (framework && framework !== "unknown") { - const _rel_path_to_config_file = path.relative(cwd, baseproj.config_file); - console.log( - `${framework} configuration found in ${_rel_path_to_config_file}` - ); - } else { - let choices: Array = [ - "flutter", - "react", - "react-native", - "vanilla", - "solid-js", - // "vue", - ]; - - if (baseproj?.framework == "unknown") { - choices = choices.filter((f) => - baseproj.allowed_frameworks.includes(f) - ); - } - - const { framework: _framework } = await prompt<{ - framework: FrameworkConfig["framework"]; - }>({ - name: "framework", - type: "select", - message: "Select framework", - // initial: baseproj?.framework, - choices: choices, - }); - framework = _framework; - } - } - - const _selection_ux_guide_msg = "(press space to select, enter to confirm)"; - switch (framework) { - case "react": { - const packages = ["styled-components", "@emotion/styled"]; - // TODO: - const { styles } = await prompt<{ styles: string[] }>({ - name: "styles", - message: "Select style " + _selection_ux_guide_msg, - type: "multiselect", - initial: baseproj?.packages ?? [], - // @ts-ignore - choices: [ - { - name: "css", - value: "css", - }, - ...packages.map((p) => { - return { - name: p, - value: p, - hint: baseproj?.packages?.includes(p) - ? " (found from package.json)" - : undefined, - }; - }), - { - name: "inline-style", - value: "inline-style", - hint: `
`, - }, - { - name: "others", - }, - // "scss", - // "less", - ], - }); - } - } - - switch (framework) { - case "react-native": - case "react": { - return { - framework: framework as "react", - language: Language.tsx, - // TODO: - styling: { - type: "styled-components", - module: "@emotion/styled", - }, - component_declaration_style: { - // TODO: - exporting_style: { - type: "export-named-functional-component", - declaration_syntax_choice: "function", - export_declaration_syntax_choice: "export", - exporting_position: "with-declaration", - }, - }, - }; - } - case "flutter": { - return { framework: "flutter", language: Language.dart }; - } - default: { - return { - framework: framework as FrameworkConfig["framework"], - } as FrameworkConfig; - } - } -} - function create_cwd_if_not_exists(cwd = process.cwd()) { if (!fs.existsSync(cwd)) { fs.mkdirSync(cwd); @@ -294,6 +181,7 @@ export * from "./init-.grida"; export * from "./init-base-project-with-teplate"; export * from "./init-config-designsource"; export * from "./init-config-designsource-figma"; +export * from "./init-config-framework"; export * from "./init-grida.config.js"; export * from "./init-package.json"; export * from "./init-pubspec.yaml"; diff --git a/cli/init/init-config-framework.ts b/cli/init/init-config-framework.ts new file mode 100644 index 00000000..19235124 --- /dev/null +++ b/cli/init/init-config-framework.ts @@ -0,0 +1,119 @@ +import path from "path"; +import { BaseProjectInfo } from "../project"; +import { prompt } from "enquirer"; +import type { FrameworkConfig } from "@grida/builder-config"; +import { Framework, Language } from "@grida/builder-platform-types"; + +export async function prompt_framework_config( + cwd, + baseproj?: BaseProjectInfo | undefined, + initialized_with_template?: boolean +): Promise { + let framework: BaseProjectInfo["framework"] = baseproj?.framework; + if (!initialized_with_template) { + if (framework && framework !== "unknown") { + const _rel_path_to_config_file = path.relative(cwd, baseproj.config_file); + console.log( + `${framework} configuration found in ${_rel_path_to_config_file}` + ); + } else { + let choices: Array = [ + "flutter", + "react", + "react-native", + "vanilla", + "solid-js", + // "vue", + ]; + + if (baseproj?.framework == "unknown") { + choices = choices.filter((f) => + baseproj.allowed_frameworks.includes(f) + ); + } + + const { framework: _framework } = await prompt<{ + framework: FrameworkConfig["framework"]; + }>({ + name: "framework", + type: "select", + message: "Select framework", + // initial: baseproj?.framework, + choices: choices, + }); + framework = _framework; + } + } + + const _selection_ux_guide_msg = "(press space to select, enter to confirm)"; + switch (framework) { + case "react": { + const packages = ["styled-components", "@emotion/styled"]; + // TODO: + const { styles } = await prompt<{ styles: string[] }>({ + name: "styles", + message: "Select style " + _selection_ux_guide_msg, + type: "multiselect", + initial: baseproj?.packages ?? [], + // @ts-ignore + choices: [ + { + name: "css", + value: "css", + }, + ...packages.map((p) => { + return { + name: p, + value: p, + hint: baseproj?.packages?.includes(p) + ? " (found from package.json)" + : undefined, + }; + }), + { + name: "inline-style", + value: "inline-style", + hint: `
`, + }, + { + name: "others", + }, + // "scss", + // "less", + ], + }); + } + } + + switch (framework) { + case "react-native": + case "react": { + return { + framework: framework as "react", + language: Language.tsx, + // TODO: + styling: { + type: "styled-components", + module: "@emotion/styled", + }, + component_declaration_style: { + // TODO: + exporting_style: { + type: "export-named-functional-component", + declaration_syntax_choice: "function", + export_declaration_syntax_choice: "export", + exporting_position: "with-declaration", + }, + }, + }; + } + case "flutter": { + return { framework: "flutter", language: Language.dart }; + } + default: { + return { + framework: framework as FrameworkConfig["framework"], + } as FrameworkConfig; + } + } +} From 8cd66a89d2888d8f45cb663fce9281c07814e523 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 17:48:39 +0900 Subject: [PATCH 05/25] add pacakge.json insert (write only) --- cli/npm/__test__/insert-dependency.test.ts | 44 ++++++ cli/npm/insert.ts | 156 +++++++++++++++++---- 2 files changed, 171 insertions(+), 29 deletions(-) create mode 100644 cli/npm/__test__/insert-dependency.test.ts diff --git a/cli/npm/__test__/insert-dependency.test.ts b/cli/npm/__test__/insert-dependency.test.ts new file mode 100644 index 00000000..45125c99 --- /dev/null +++ b/cli/npm/__test__/insert-dependency.test.ts @@ -0,0 +1,44 @@ +import path from "path"; +import { add_dependencies } from "../insert"; +import fs from "fs"; +test("add dependency to empty package.json (write only)", async () => { + // copy (overwrite) file from template for testing + const template = path.join(__dirname, "./package.empty.json"); + const target = path.join(__dirname, "./package.test.empty.json"); + fs.copyFileSync(template, target, fs.constants.COPYFILE_FICLONE); + + const { manifest } = await add_dependencies(target, { + dependencies: [ + { name: "@emotion/react", version: "latest" }, + { name: "@emotion/styled", version: "latest" }, + ], + devDependencies: [{ name: "grida", version: "latest" }], + type: "write-only", + }); + expect( + "@emotion/react" in manifest.dependencies && + "@emotion/styled" in manifest.dependencies && + "grida" in manifest.devDependencies + ).toBe(true); + + // remove file after testing + fs.unlinkSync(target); +}); + +test("add dependency to fullfilled package.json (write only)", async () => { + const { updated, installed } = await add_dependencies( + path.join(__dirname, "./package.test.fulfilled.json"), + { + dependencies: [ + { name: "@emotion/react", version: "latest" }, + { name: "@emotion/styled", version: "latest" }, + ], + devDependencies: [{ name: "grida", version: "latest" }], + type: "write-only", + } + ); + + expect(updated.dependencies.length).toBe(0); + expect(updated.devDependencies.length).toBe(0); + expect(installed).toBe(false); +}); diff --git a/cli/npm/insert.ts b/cli/npm/insert.ts index 6c0d6ef0..8eb82480 100644 --- a/cli/npm/insert.ts +++ b/cli/npm/insert.ts @@ -1,6 +1,9 @@ -import { spawn } from "child_process"; -import fs from "fs"; +import { PackageManifest } from "@web-builder/nodejs"; +import { spawn, spawnSync } from "child_process"; import path from "path"; +import fs from "fs"; +import fetch from "node-fetch"; +import assert from "assert"; type Dependency = { name: string; @@ -9,63 +12,133 @@ type Dependency = { type InstallOption = | { - npmClient: "npm" | "yarn" | "pnpm"; - type: "install"; - } - | { - type: "update-package.json"; - installAfter: false; + type: "write-only"; } | { - type: "update-package.json"; - installAfter: true; + type: "write-and-install"; npmClient: "npm" | "yarn" | "pnpm"; }; +interface AddDependencyResult { + error?: Error; + installed: boolean; + before: PackageManifest; + manifest: PackageManifest; + updated: { + dependencies: Dependency[]; + devDependencies: Dependency[]; + }; +} + /** * add requested dependencies to package.json * * - add with install - do not modify package.json, run install command instead * - don't add with install - */ -export function add_dependencies( - cwd = process.cwd(), +export async function add_dependencies( + packagejson: string, { - dependencies, - devDependencies, + dependencies = [], + devDependencies = [], ...installconfig }: { - dependencies: Dependency[]; - devDependencies: Dependency[]; + dependencies?: Dependency[]; + devDependencies?: Dependency[]; } & InstallOption -) { - const packagejson = path.resolve(cwd, "package.json"); - if (!fs.existsSync(packagejson)) { - throw new Error(`package.json not found in ${cwd}`); - } +): Promise { + let installed = false; const manifest = require(packagejson); - const deps = new Set(Object.keys(manifest.dependencies || {})); - const devdeps = new Set(Object.keys(manifest.devDependencies || {})); + const prev_manifest = { ...manifest }; + const prev_deps = new Set(Object.keys(manifest.dependencies || {})); + const prev_devdeps = new Set(Object.keys(manifest.devDependencies || {})); + + // targets not in prev_deps or prev_devdeps + const target_deps = dependencies.filter( + (dep) => !prev_deps.has(dep.name) && !prev_devdeps.has(dep.name) + ); + const target_devdeps = devDependencies.filter( + (dep) => !prev_deps.has(dep.name) && !prev_devdeps.has(dep.name) + ); + + async function makeDepsMap(deps: Dependency[]) { + return await deps.reduce( + async (acc, dep) => ({ + ...(await acc), + [dep.name]: "^" + (await version(dep)), + }), + {} + ); + } switch (installconfig.type) { - case "install": { + case "write-only": { + // write target deps & devdeps to package.json + // sort with alphabetical order + + // add deps + const adddeps = await makeDepsMap(target_deps); + + manifest.dependencies = { + ...manifest.dependencies, + ...adddeps, + }; + manifest.dependencies = sort_az(manifest.dependencies); + + // add devdeps + manifest.devDependencies = { + ...manifest.devDependencies, + ...(await makeDepsMap(target_devdeps)), + }; + manifest.devDependencies = sort_az(manifest.devDependencies); + + // write package.json + await fs.promises.writeFile( + packagejson, + JSON.stringify(manifest, null, 4) + ); + + break; + } + case "write-and-install": { + assert( + path.parse(packagejson).base === "package.json", + "installation requires input package.json file path to be exact package.json file" + ); + // let the spawned process handle the write & install + const cwd = path.dirname(packagejson); const { npmClient } = installconfig; const install = npmClient === "npm" ? "install" : "add"; // deps - if (dependencies.length > 0) { + if (target_deps.length > 0) { + spawnSync(npmClient, [install, ...target_deps.map((d) => d.name)], { + cwd, + }); + installed = true; } - spawn(npmClient, [install, ...dependencies.map((d) => d.name)], { cwd }); // devdeps - if (devDependencies.length > 0) { - spawn( + if (target_devdeps.length > 0) { + spawnSync( npmClient, - [install, dev_flag[npmClient], ...devDependencies.map((d) => d.name)], + [install, dev_flag[npmClient], ...target_devdeps.map((d) => d.name)], { cwd } ); + installed = true; } + break; } } + + return { + installed: installed, + before: prev_manifest, + manifest: require(packagejson), + updated: { + dependencies: [...target_deps], + devDependencies: [...target_devdeps], + }, + }; } const dev_flag = { @@ -73,3 +146,28 @@ const dev_flag = { yarn: "--dev", pnpm: "--D", } as const; + +/** + * get latest version from npm + */ +async function latest(pkg: string): Promise { + return ( + await (await fetch(`https://registry.npmjs.org/${pkg}/latest`)).json() + ).version; +} + +async function version(d: Dependency): Promise { + if (d.version !== "latest") { + return d.version; + } else if (d.version === "latest") { + return await latest(d.name); + } else { + return await latest(d.name); + } +} + +function sort_az(obj: object) { + return Object.keys(obj) + .sort() + .reduce((acc, key) => ({ ...acc, [key]: obj[key] }), {}); +} From fad45134c682f93212ab844f606a238dd920c929 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 18:45:50 +0900 Subject: [PATCH 06/25] add npm package manager --- cli/npm/__test__/insert-dependency.test.ts | 66 +++++++- cli/npm/insert.ts | 166 ++++++++++++++------- cli/npm/install-npm.ts | 52 +++++++ cli/npm/type.ts | 4 + 4 files changed, 230 insertions(+), 58 deletions(-) create mode 100644 cli/npm/install-npm.ts create mode 100644 cli/npm/type.ts diff --git a/cli/npm/__test__/insert-dependency.test.ts b/cli/npm/__test__/insert-dependency.test.ts index 45125c99..45dc4467 100644 --- a/cli/npm/__test__/insert-dependency.test.ts +++ b/cli/npm/__test__/insert-dependency.test.ts @@ -1,13 +1,16 @@ import path from "path"; import { add_dependencies } from "../insert"; import fs from "fs"; +// max 30s +jest.setTimeout(30000); + test("add dependency to empty package.json (write only)", async () => { // copy (overwrite) file from template for testing const template = path.join(__dirname, "./package.empty.json"); const target = path.join(__dirname, "./package.test.empty.json"); fs.copyFileSync(template, target, fs.constants.COPYFILE_FICLONE); - const { manifest } = await add_dependencies(target, { + const { manifest: _manifest } = await add_dependencies(target, { dependencies: [ { name: "@emotion/react", version: "latest" }, { name: "@emotion/styled", version: "latest" }, @@ -15,11 +18,44 @@ test("add dependency to empty package.json (write only)", async () => { devDependencies: [{ name: "grida", version: "latest" }], type: "write-only", }); + const manifest = _manifest(); + expect( + "@emotion/react" in manifest.dependencies && + "@emotion/styled" in manifest.dependencies && + "grida" in manifest.devDependencies + ).toBe(true); + + // remove file after testing + fs.unlinkSync(target); +}); + +test("add dependency to empty package.json (with install)", async () => { + // copy file from template for testing + const template = path.join(__dirname, "./package.empty.json"); + const target = path.join( + __dirname, + "sub-dir-for-npm-install", + "package.json" + ); + fs.copyFileSync(template, target, fs.constants.COPYFILE_FICLONE); + + const { manifest: _manifest, installed } = await add_dependencies(target, { + dependencies: [ + { name: "@emotion/react", version: "latest" }, + { name: "@emotion/styled", version: "latest" }, + ], + devDependencies: [{ name: "grida", version: "latest" }], + type: "write-and-install", + npmClient: "npm", + }); + + const manifest = _manifest(); expect( "@emotion/react" in manifest.dependencies && "@emotion/styled" in manifest.dependencies && "grida" in manifest.devDependencies ).toBe(true); + expect(installed).toBe(true); // remove file after testing fs.unlinkSync(target); @@ -42,3 +78,31 @@ test("add dependency to fullfilled package.json (write only)", async () => { expect(updated.devDependencies.length).toBe(0); expect(installed).toBe(false); }); + +// test("add dependency to fullfilled package.json (with install)", async () => { +// // copy file from template for testing +// const template = path.join(__dirname, "./package.test.fulfilled.json"); +// const target = path.join( +// __dirname, +// "sub-dir-for-npm-install", +// "package.json" +// ); +// fs.copyFileSync(template, target, fs.constants.COPYFILE_FICLONE); + +// const { updated, installed } = await add_dependencies(target, { +// dependencies: [ +// { name: "@emotion/react", version: "latest" }, +// { name: "@emotion/styled", version: "latest" }, +// ], +// devDependencies: [{ name: "grida", version: "latest" }], +// type: "with-npm-client", +// npmClient: "npm", +// }); + +// expect(updated.dependencies.length).toBe(0); +// expect(updated.devDependencies.length).toBe(0); +// expect(installed).toBe(false); + +// // remove file after testing +// fs.unlinkSync(target); +// }); diff --git a/cli/npm/insert.ts b/cli/npm/insert.ts index 8eb82480..87012e5d 100644 --- a/cli/npm/insert.ts +++ b/cli/npm/insert.ts @@ -1,14 +1,10 @@ import { PackageManifest } from "@web-builder/nodejs"; -import { spawn, spawnSync } from "child_process"; +import { npmInsatll } from "./install-npm"; import path from "path"; import fs from "fs"; import fetch from "node-fetch"; import assert from "assert"; - -type Dependency = { - name: string; - version?: string | "latest" | "*"; -}; +import { Dependency } from "./type"; type InstallOption = | { @@ -16,14 +12,22 @@ type InstallOption = } | { type: "write-and-install"; - npmClient: "npm" | "yarn" | "pnpm"; + npmClient: "npm"; + } + | { + type: "with-npm-client"; + npmClient: "npm"; // TODO: support yarn and pnpm }; interface AddDependencyResult { error?: Error; installed: boolean; before: PackageManifest; - manifest: PackageManifest; + /** + * if the dependency is added by npm i, then the package.json file requires some time to be written. on caller, you'll have to wait and resolve the manifest file after when this is complete. + * This is not provided by this function. + */ + manifest: () => PackageManifest; updated: { dependencies: Dependency[]; devDependencies: Dependency[]; @@ -33,8 +37,11 @@ interface AddDependencyResult { /** * add requested dependencies to package.json * - * - add with install - do not modify package.json, run install command instead - * - don't add with install - + * - type: write-only - only write the dependencies to package.json + * - type: write-and-install - write the dependencies to package.json and install the dependencies with npm client afterwards + * - type: with-npm-client - install the dependencies with npm client and return the manifest file + * - WARNING: this does not return the proper manifest. the installation requires extra time to be fully write to package.json.. + * */ export async function add_dependencies( packagejson: string, @@ -47,7 +54,15 @@ export async function add_dependencies( devDependencies?: Dependency[]; } & InstallOption ): Promise { + if ("npmClient" in installconfig) { + assert( + path.parse(packagejson).base === "package.json", + "installation requires input package.json file path to be exact package.json file" + ); + } + let installed = false; + const cwd = path.dirname(packagejson); const manifest = require(packagejson); const prev_manifest = { ...manifest }; const prev_deps = new Set(Object.keys(manifest.dependencies || {})); @@ -71,61 +86,70 @@ export async function add_dependencies( ); } + const write_file = async () => { + // write target deps & devdeps to package.json + // sort with alphabetical order + + // add deps + const adddeps = await makeDepsMap(target_deps); + + manifest.dependencies = { + ...manifest.dependencies, + ...adddeps, + }; + manifest.dependencies = sort_az(manifest.dependencies); + + // add devdeps + manifest.devDependencies = { + ...manifest.devDependencies, + ...(await makeDepsMap(target_devdeps)), + }; + manifest.devDependencies = sort_az(manifest.devDependencies); + + // write package.json + await fs.promises.writeFile(packagejson, JSON.stringify(manifest, null, 4)); + }; + switch (installconfig.type) { case "write-only": { - // write target deps & devdeps to package.json - // sort with alphabetical order - - // add deps - const adddeps = await makeDepsMap(target_deps); - - manifest.dependencies = { - ...manifest.dependencies, - ...adddeps, - }; - manifest.dependencies = sort_az(manifest.dependencies); - - // add devdeps - manifest.devDependencies = { - ...manifest.devDependencies, - ...(await makeDepsMap(target_devdeps)), - }; - manifest.devDependencies = sort_az(manifest.devDependencies); - - // write package.json - await fs.promises.writeFile( - packagejson, - JSON.stringify(manifest, null, 4) - ); - + await write_file(); break; } case "write-and-install": { - assert( - path.parse(packagejson).base === "package.json", - "installation requires input package.json file path to be exact package.json file" - ); + await write_file(); + await npmInsatll(cwd, [], { + cache: true, + }); + installed = true; + break; + } + case "with-npm-client": { // let the spawned process handle the write & install - const cwd = path.dirname(packagejson); const { npmClient } = installconfig; - const install = npmClient === "npm" ? "install" : "add"; - // deps - if (target_deps.length > 0) { - spawnSync(npmClient, [install, ...target_deps.map((d) => d.name)], { - cwd, - }); - installed = true; + switch (npmClient) { + case "npm": { + if (target_deps.length > 0) { + await npmInsatll(cwd, target_deps, { + save: true, + }); + installed = true; + } + + // devdeps + if (target_devdeps.length > 0) { + await npmInsatll(cwd, target_devdeps, { + save: true, + saveDev: true, + }); + installed = true; + } + } } + // const install = npmClient === "npm" ? "install" : "add"; + // deps + + // check if package.json is updated by the spawned process - // devdeps - if (target_devdeps.length > 0) { - spawnSync( - npmClient, - [install, dev_flag[npmClient], ...target_devdeps.map((d) => d.name)], - { cwd } - ); - installed = true; - } break; } } @@ -133,7 +157,7 @@ export async function add_dependencies( return { installed: installed, before: prev_manifest, - manifest: require(packagejson), + manifest: () => require(packagejson), updated: { dependencies: [...target_deps], devDependencies: [...target_devdeps], @@ -171,3 +195,31 @@ function sort_az(obj: object) { .sort() .reduce((acc, key) => ({ ...acc, [key]: obj[key] }), {}); } + +/** + * the yarn add or npm install process needs extra time after the child process is complete for the package.json file is to be updated + * this function checks if the process is fully complete. + * @param snapshot + * @param packagejson + * @param timeout + * @returns + */ +function is_install_complete( + snapshot: PackageManifest, + packagejson: string, + timeout = 5000 +): Promise { + return new Promise((resolve) => { + const interval = setInterval(() => { + const manifest = require(packagejson); + // if there is change in file, it means installation is complete + if (JSON.stringify(snapshot) !== JSON.stringify(manifest)) { + clearInterval(interval); + resolve(true); + } + }, 100); + setTimeout(() => { + resolve(false); + }, timeout); + }); +} diff --git a/cli/npm/install-npm.ts b/cli/npm/install-npm.ts new file mode 100644 index 00000000..247eb1c8 --- /dev/null +++ b/cli/npm/install-npm.ts @@ -0,0 +1,52 @@ +/// +/// oriented from - https://github.com/yoshuawuyts/npm-install-package (MIT LICENSE) +/// updated by universe (MIT) +/// + +import { Dependency } from "./type"; +import util from "util"; + +const exec = util.promisify(require("child_process").exec); + +export async function npmInsatll( + cwd = process.cwd(), + deps?: Dependency | Dependency[], + opts?: { + save?: boolean; + saveDev?: boolean; + global?: boolean; + cache?: boolean; + verbose?: boolean; + } +) { + deps = deps ? (Array.isArray(deps) ? deps : [deps]) : []; + opts = opts ?? {}; + + var args = []; + if (opts.save) args.push("-S"); + if (opts.saveDev) args.push("-D"); + if (opts.global) args.push("-g"); + if (opts.cache) args.push("--cache-min Infinity"); + + if (opts.verbose) { + deps.forEach(function (dep) { + process.stdout.write("pkg: " + dep.name + "\n"); + }); + } + + var cliArgs = ["npm i"] + .concat( + args, + deps.map((d) => { + if (d.version) { + return d.name + "@" + d.version; + } else { + return d.name; + } + }) + ) + .join(" "); + await exec(cliArgs, { + cwd, + }); +} diff --git a/cli/npm/type.ts b/cli/npm/type.ts new file mode 100644 index 00000000..c42ccc4a --- /dev/null +++ b/cli/npm/type.ts @@ -0,0 +1,4 @@ +export type Dependency = { + name: string; + version?: string | "latest" | "*"; +}; From 6813472f2c5cac0182148795d4b410f90bbf34e3 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 19:26:58 +0900 Subject: [PATCH 07/25] add init package.json --- cli/init/init-package.json.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/cli/init/init-package.json.ts b/cli/init/init-package.json.ts index e69de29b..baf0a601 100644 --- a/cli/init/init-package.json.ts +++ b/cli/init/init-package.json.ts @@ -0,0 +1,33 @@ +import path from "path"; +import { add_dependencies, Dependency } from "../npm"; +export async function init_package_json( + cwd = process.cwd(), + { + dependencies, + }: { + dependencies?: Dependency[]; + } +) { + const packagejson = path.join(cwd, "package.json"); + + const { manifest, installed, updated } = await add_dependencies(packagejson, { + dependencies: dependencies ?? [], + devDependencies: [ + { + name: "grida", + version: "latest", + }, + ], + type: "write-only", + }); + + if (updated.dependencies?.length > 0) { + console.log(` + Added dependencies [${updated.dependencies + .map((d) => `${d.name}@${d.version}`) + .join( + ", " + )}] to package.json. Run \`npm install\` or \`yarn add\` to resolve. + `); + } +} From dd1c71262cefeaa75ab45467d0c09f482911f118 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 19:27:15 +0900 Subject: [PATCH 08/25] add global error message handling --- cli/index.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/cli/index.ts b/cli/index.ts index 2398071a..a1ee225c 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -1,11 +1,21 @@ #!/usr/bin/env node import cli from "./bin"; +import chalk from "chalk"; export type { GridaConfig } from "./config"; -process.on("SIGINT", () => { - process.exit(0); // now the "exit" event will fire -}); +process + .on("SIGINT", () => { + process.exit(0); // now the "exit" event will fire + }) + .on("uncaughtException", (err) => { + console.log(chalk.bgRed(err.message ?? "")); + process.exit(1); + }) + .on("unhandledRejection", (err: Error, p) => { + console.error(chalk.bgRed(err.message ?? "")); + process.exit(1); + }); // if main if (require.main === module) { From dce8649fef421376d988f41030d7cc3f6bc75ab8 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 19:27:43 +0900 Subject: [PATCH 09/25] update logging --- cli/bin.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/bin.ts b/cli/bin.ts index 5c3a2ea9..b92bd72d 100644 --- a/cli/bin.ts +++ b/cli/bin.ts @@ -16,6 +16,7 @@ import { checkForUpdate } from "./update"; import { login, logout } from "./auth"; import { startFlutterDaemonServer } from "./flutter/daemon"; import { parseFileId } from "@design-sdk/figma-url"; +import chalk from "chalk"; function loadenv(argv) { const { cwd } = argv; @@ -23,7 +24,7 @@ function loadenv(argv) { const dotenvpath = path.join(cwd, ".env"); if (fs.existsSync(dotenvpath)) { dotenv.config({ path: dotenvpath }); - console.log("Loaded .env file"); + console.info(chalk.dim("Loaded .env file")); } } From a634d0bffc7f4de944871f80ccdd59d06a2cab6f Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 19:28:19 +0900 Subject: [PATCH 10/25] add npm initializer based on givven framework config --- cli/init/index.ts | 36 +++++++++++- cli/init/init-config-framework.ts | 93 +++++++++++++++++++++++++++---- cli/npm/index.ts | 2 + 3 files changed, 119 insertions(+), 12 deletions(-) diff --git a/cli/init/index.ts b/cli/init/index.ts index e4ace97b..4d155fe6 100644 --- a/cli/init/index.ts +++ b/cli/init/index.ts @@ -17,6 +17,7 @@ import { create_grida_config_js } from "./init-grida.config.js"; import { init_dotgrida } from "./init-.grida"; import { init_gitignore } from "./init-.gitignore"; import { prompt_framework_config } from "./init-config-framework"; +import { init_package_json } from "./init-package.json"; export async function init( cwd = process.cwd(), @@ -49,8 +50,16 @@ export async function init( exit(0); } else { const { created, cwd: newcwd, name } = _; - if (created) + if (created) { + console.log("\n\n\n"); + console.info( + chalk.bgGreen( + "Fresh project created. Resuming `grida init` process." + ) + ); + console.log(`\n`); return init(newcwd, { name, initialized_with_template: true }); + } } return; } @@ -100,6 +109,16 @@ export async function init( init_gitignore(cwd, { template: framework_gitignore_templates[config_framework.framework], }); // init .gitignore first (why? cause we're dealing with user's local directory here. we don't want to mass things up. .gitignore first.) + + if (is_node_project(config_framework.framework)) { + await init_package_json(cwd, { + dependencies: config_framework.packages.map((p) => ({ + name: p, + version: "latest", + })), + }); + } + // creates grida.config.js create_grida_config_js(cwd, { name: name, @@ -175,6 +194,21 @@ function create_grida_fallback_dir( }; } +function is_node_project(framework: FrameworkConfig["framework"]) { + switch (framework) { + case "flutter": + return false; + case "react": + case "react-native": + case "solid-js": + return true; + case "vanilla": + case "preview": + default: + return false; + } +} + export * from "./init-.env"; export * from "./init-.gitignore"; export * from "./init-.grida"; diff --git a/cli/init/init-config-framework.ts b/cli/init/init-config-framework.ts index 19235124..bace80e4 100644 --- a/cli/init/init-config-framework.ts +++ b/cli/init/init-config-framework.ts @@ -2,13 +2,18 @@ import path from "path"; import { BaseProjectInfo } from "../project"; import { prompt } from "enquirer"; import type { FrameworkConfig } from "@grida/builder-config"; -import { Framework, Language } from "@grida/builder-platform-types"; +import { Language } from "@grida/builder-platform-types"; +import { ReactStylingStrategy } from "@grida/builder-config/framework-react"; + +type FrameworkConfigResult = FrameworkConfig & { + packages: string[]; +}; export async function prompt_framework_config( cwd, baseproj?: BaseProjectInfo | undefined, initialized_with_template?: boolean -): Promise { +): Promise { let framework: BaseProjectInfo["framework"] = baseproj?.framework; if (!initialized_with_template) { if (framework && framework !== "unknown") { @@ -59,12 +64,12 @@ export async function prompt_framework_config( choices: [ { name: "css", - value: "css", + message: "css", }, ...packages.map((p) => { return { + message: p, name: p, - value: p, hint: baseproj?.packages?.includes(p) ? " (found from package.json)" : undefined, @@ -72,7 +77,7 @@ export async function prompt_framework_config( }), { name: "inline-style", - value: "inline-style", + message: "inline-style", hint: `
`, }, { @@ -82,19 +87,60 @@ export async function prompt_framework_config( // "less", ], }); + + // TODO: add multi styling config sypport + let default_style: ReactStylingStrategy = { + type: "styled-components", + module: "@emotion/styled", + }; + let required_packages = ["@emotion/styled", "@emotion/react"]; + if (styles.includes("@emotion/styled")) { + default_style = { + type: "styled-components", + module: "@emotion/styled", + }; + required_packages = ["@emotion/styled", "@emotion/react"]; + } else if (styles.includes("styled-components")) { + default_style = { + type: "styled-components", + module: "styled-components", + }; + required_packages = ["styled-components"]; + } else if (styles.includes("inline-css")) { + default_style = { + type: "inline-css", + }; + required_packages = []; + } + + return { + framework: framework as "react", + language: Language.tsx, + // TODO: + styling: default_style, + component_declaration_style: { + // TODO: + exporting_style: { + type: "export-named-functional-component", + declaration_syntax_choice: "function", + export_declaration_syntax_choice: "export", + exporting_position: "with-declaration", + }, + }, + packages: required_packages, + }; } } switch (framework) { - case "react-native": - case "react": { + case "react-native": { return { - framework: framework as "react", + framework: framework, language: Language.tsx, // TODO: styling: { type: "styled-components", - module: "@emotion/styled", + module: "@emotion/native", }, component_declaration_style: { // TODO: @@ -105,15 +151,40 @@ export async function prompt_framework_config( exporting_position: "with-declaration", }, }, + shadow: { + type: "react-native", + module: "react-native", + }, + gradient_text: { + linear: { + module: "react-native-text-gradient", + }, + radial: ["fallback-to-svg"], + }, + gradient: { + linear: { + module: "react-native-linear-gradient", + }, + radial: { + module: "react-native-radial-gradient", + }, + }, + svg: { + module: "react-native-svg", + prefer_mode: "svg-with-path", + }, + packages: ["@emotion/styled", "@emotion/react"], }; + break; } case "flutter": { - return { framework: "flutter", language: Language.dart }; + return { framework: "flutter", language: Language.dart, packages: [] }; } default: { return { framework: framework as FrameworkConfig["framework"], - } as FrameworkConfig; + package: [], + } as any as FrameworkConfigResult; } } } diff --git a/cli/npm/index.ts b/cli/npm/index.ts index 72095083..7245064b 100644 --- a/cli/npm/index.ts +++ b/cli/npm/index.ts @@ -1 +1,3 @@ export * from "./locate"; +export * from "./insert"; +export * from "./type"; From 4c21c99660baa8dea4b04a920da02688be0cf188 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 19:28:23 +0900 Subject: [PATCH 11/25] organize --- cli/init/init-base-project-with-teplate.ts | 9 +++++++-- cli/init/init-config-designsource.ts | 5 ++++- cli/init/init-pubspec.yaml.ts | 1 + cli/npm/__test__/package.empty.json | 4 ++++ cli/npm/__test__/package.test.fulfilled.json | 10 ++++++++++ cli/npm/__test__/sub-dir-for-npm-install/.gitignore | 2 ++ cli/package.json | 3 ++- 7 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 cli/npm/__test__/package.empty.json create mode 100644 cli/npm/__test__/package.test.fulfilled.json create mode 100644 cli/npm/__test__/sub-dir-for-npm-install/.gitignore diff --git a/cli/init/init-base-project-with-teplate.ts b/cli/init/init-base-project-with-teplate.ts index d81e1ba5..17a7dda0 100644 --- a/cli/init/init-base-project-with-teplate.ts +++ b/cli/init/init-base-project-with-teplate.ts @@ -1,6 +1,7 @@ import { spawnSync, SpawnSyncOptions } from "child_process"; import { prompt } from "enquirer"; import path from "path"; +import fs from "fs"; import { binexists } from "../_utils/bin-exists"; export async function init_base_project_with_template( @@ -32,7 +33,6 @@ export async function init_base_project_with_template( const template: string = _["template"]; if (template === "cancel") { - console.log("Please run `grida init` again after creating a project."); return "exit"; } @@ -43,9 +43,14 @@ export async function init_base_project_with_template( type: "input", }); - // TODO: check if binary is installed first. + if (fs.existsSync(path.join(cwd, name))) { + throw new Error( + `Failed to create fresh project. directory with name "${name}" already exists.` + ); + } create_cwd_if_not_exists(cwd); + // TODO: check if binary is installed first. const __spawan_cfg: SpawnSyncOptions = { stdio: "inherit", cwd }; switch (template) { case "flutter": { diff --git a/cli/init/init-config-designsource.ts b/cli/init/init-config-designsource.ts index 4c0e0abf..f28bc791 100644 --- a/cli/init/init-config-designsource.ts +++ b/cli/init/init-config-designsource.ts @@ -29,7 +29,10 @@ export async function prompt_designsource_config(): Promise }; } default: { - throw new Error(`Sorry, ${provider} is not supported yet.`); + console.log( + `grida for ${provider} is in private beta. If you want to try it out, please submit this form - https://forms.gle/BNtCCVBUSAYaTtSb7` + ); + process.exit(0); } } } diff --git a/cli/init/init-pubspec.yaml.ts b/cli/init/init-pubspec.yaml.ts index e69de29b..60449622 100644 --- a/cli/init/init-pubspec.yaml.ts +++ b/cli/init/init-pubspec.yaml.ts @@ -0,0 +1 @@ +export function init_pubspec_yaml() {} diff --git a/cli/npm/__test__/package.empty.json b/cli/npm/__test__/package.empty.json new file mode 100644 index 00000000..b7e0179b --- /dev/null +++ b/cli/npm/__test__/package.empty.json @@ -0,0 +1,4 @@ +{ + "name": "empty-package", + "description": "this file will be copied to package.test.empty.json for testing" +} \ No newline at end of file diff --git a/cli/npm/__test__/package.test.fulfilled.json b/cli/npm/__test__/package.test.fulfilled.json new file mode 100644 index 00000000..f643326d --- /dev/null +++ b/cli/npm/__test__/package.test.fulfilled.json @@ -0,0 +1,10 @@ +{ + "name": "package-with-deps", + "dependencies": { + "@emotion/react": "^11.10.0", + "@emotion/styled": "^11.10.0" + }, + "devDependencies": { + "grida": "^0.0.15" + } +} \ No newline at end of file diff --git a/cli/npm/__test__/sub-dir-for-npm-install/.gitignore b/cli/npm/__test__/sub-dir-for-npm-install/.gitignore new file mode 100644 index 00000000..515bcd4f --- /dev/null +++ b/cli/npm/__test__/sub-dir-for-npm-install/.gitignore @@ -0,0 +1,2 @@ +package.json +package-lock.json \ No newline at end of file diff --git a/cli/package.json b/cli/package.json index ac505060..49a34268 100644 --- a/cli/package.json +++ b/cli/package.json @@ -26,6 +26,7 @@ "scripts": { "clean": "rimraf dist", "dev": "ts-node index.ts", + "grida": "yarn dev", "dev:watch": "ts-node-dev index.ts --watch", "test": "jest", "build": "ncc build index.ts -o dist -e keytar -e glob -e dotenv", @@ -55,4 +56,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file From 4a4b60ad79490ec7cc8e7113f6a65c1e1b1faa89 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 19:32:07 +0900 Subject: [PATCH 12/25] v0.0.16 --- cli/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/package.json b/cli/package.json index 49a34268..78d6d820 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "grida", - "version": "0.0.15", + "version": "0.0.16", "private": false, "license": "Apache-2.0", "description": "grida CLI", @@ -56,4 +56,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} From d4e02051d45ffd570e7a2a0c8eddc710b279d888 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 19:47:07 +0900 Subject: [PATCH 13/25] update readme --- cli/README.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/cli/README.md b/cli/README.md index 2476a150..72f5d516 100644 --- a/cli/README.md +++ b/cli/README.md @@ -8,18 +8,23 @@ Visit https://grida.co/cli for more information. npm install -g grida ``` +## Documentation + +Visit https://grida.co/docs/cli + ## Commands -| Commands | | | -| -------------------- | --------------------------------------- | ---------------------------------------------------- | -| `grida code react` | convert input uri (file or url) to code | `designto react https://www.figma.com/files/XXX` | -| `grida code rn` | convert input uri (file or url) to code | `designto rn https://www.figma.com/files/XXX` | -| `grida code vue` | convert input uri (file or url) to code | `grida code vue https://www.figma.com/files/XXX` | -| `grida code svelte` | convert input uri (file or url) to code | `grida code svelte https://www.figma.com/files/XXX` | -| `grida code solid` | convert input uri (file or url) to code | `grida code flutter https://www.figma.com/files/XXX` | -| `grida code flutter` | help | `designto flutter https://www.figma.com/files/XXX` | -| `grida code auth` | signin to design services | `auto` \| `figma` \| `sketch` \| `xd` | -| `grida code init` | configure the preferences | +| Commands | | | +| ----------------------- | --------------------------------------- | ----------------------------------------------------- | +| `grida init` | configure the preferences | | +| `grida login` | signin to design services | `auto` \| `figma` \| `sketch` \| `xd` | +| `grida add [modules..]` | add new modules to existing project | `grida add` | +| `grida code react` | convert input uri (file or url) to code | `grida code react https://www.figma.com/files/XXX` | +| `grida code rn` | convert input uri (file or url) to code | `grida code rn https://www.figma.com/files/XXX` | +| `grida code vue` | convert input uri (file or url) to code | `grida code vue https://www.figma.com/files/XXX` | +| `grida code svelte` | convert input uri (file or url) to code | `grida code svelte https://www.figma.com/files/XXX` | +| `grida code solid-js` | convert input uri (file or url) to code | `grida code solid-js https://www.figma.com/files/XXX` | +| `grida code flutter` | help | `grida code flutter https://www.figma.com/files/XXX` | ## Args From 2d6540a36873bb21d8ad7262e1ac5a7c14c6e727 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 19:48:15 +0900 Subject: [PATCH 14/25] rm cache flag when installing npm --- cli/npm/insert.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cli/npm/insert.ts b/cli/npm/insert.ts index 87012e5d..07edf573 100644 --- a/cli/npm/insert.ts +++ b/cli/npm/insert.ts @@ -117,9 +117,7 @@ export async function add_dependencies( } case "write-and-install": { await write_file(); - await npmInsatll(cwd, [], { - cache: true, - }); + await npmInsatll(cwd, [], {}); installed = true; break; } From 6e5f53ea799fe3a26aed005af404c6e1528f501b Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 13 Aug 2022 19:49:09 +0900 Subject: [PATCH 15/25] v0.0.18 --- cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/package.json b/cli/package.json index 78d6d820..a6e700b2 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "grida", - "version": "0.0.16", + "version": "0.0.18", "private": false, "license": "Apache-2.0", "description": "grida CLI", From d3b2b9122a97e36b293b29cb8e57302a54b8e819 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 15 Aug 2022 22:44:52 +0900 Subject: [PATCH 16/25] add fpat doc link --- cli/init/init-config-designsource-figma.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cli/init/init-config-designsource-figma.ts b/cli/init/init-config-designsource-figma.ts index 031865be..b8a736c5 100644 --- a/cli/init/init-config-designsource-figma.ts +++ b/cli/init/init-config-designsource-figma.ts @@ -38,13 +38,14 @@ export async function prompt_figma_personal_access_token( ): Promise { const _ = await prompt({ name: "figma-personal-access-token", - message: "Please enter your figma personal access token.", + message: + "Please enter your figma personal access token. (🤔 https://bit.ly/figma-personal-access-token)", type: "password", // @ts-ignore async validate(value) { // it's usually 43 chars long e.g "xxxxxx-xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx" if (!value || value.length < 40 || value.trim().includes(" ")) { - return "Please enter your figma personal access token. How to 👉 https://grida.co/docs/with-figma/guides/how-to-get-personal-access-token"; + return "Please enter your figma personal access token. How to 👉 https://bit.ly/figma-personal-access-token"; } const validationClient = FigmaApiClient({ From 543ee5359e95049be38f5aef262706b6f0005e6a Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 16 Aug 2022 04:15:23 +0900 Subject: [PATCH 17/25] add login & logout to grida cli --- cli/.public-credentials/readme.md | 1 + cli/auth/api.ts | 13 +++++++------ cli/auth/login.ts | 1 + cli/bin.ts | 4 ++-- cli/index.ts | 31 +++++++++++++++++++------------ cli/package.json | 10 ++++++---- cli/scripts/copy-env.js | 25 +++++++++++++++++++++++++ cli/tsconfig.json | 2 +- cli/yarn.lock | 25 ++++++++++++++++++++++++- 9 files changed, 86 insertions(+), 26 deletions(-) create mode 100644 cli/.public-credentials/readme.md create mode 100644 cli/scripts/copy-env.js diff --git a/cli/.public-credentials/readme.md b/cli/.public-credentials/readme.md new file mode 100644 index 00000000..a9907aac --- /dev/null +++ b/cli/.public-credentials/readme.md @@ -0,0 +1 @@ +https://bit.ly/3dxp0xW diff --git a/cli/auth/api.ts b/cli/auth/api.ts index ae0a775e..4ced99e9 100644 --- a/cli/auth/api.ts +++ b/cli/auth/api.ts @@ -9,8 +9,9 @@ import Axios from "axios"; import { machineIdSync } from "node-machine-id"; import { AuthStore } from "./store"; -const PROXY_AUTH_REQUEST_SECRET = - process.env.GRIDA_FIRST_PARTY_PROXY_AUTH_REQUEST_TOTP_SECRET; +// it is ok to load dynamically since its cli env. +const PROXY_AUTH_REQUEST_SECRET = () => + process.env.PUBLIC_GRIDA_FIRST_PARTY_PROXY_AUTH_REQUEST_TOTP_SECRET; function _termenv(): "vscode" | "terminal" | "unknown" { switch (process.env.TERM_PROGRAM) { @@ -33,7 +34,7 @@ function _make_request(): AuthProxySessionStartRequest { export async function startAuthenticationSession(): Promise { return __auth_proxy.openProxyAuthSession( - PROXY_AUTH_REQUEST_SECRET, + PROXY_AUTH_REQUEST_SECRET(), _make_request() ); } @@ -42,7 +43,7 @@ export async function startAuthenticationWithSession( session: AuthProxySessionStartResult ) { const result = await __auth_proxy.requesetProxyAuthWithSession( - PROXY_AUTH_REQUEST_SECRET, + PROXY_AUTH_REQUEST_SECRET(), session, _make_request() ); @@ -69,7 +70,7 @@ export async function getAccessToken(): Promise { export async function checkAuthSession(session: string): Promise { // TODO: const res = await __auth_proxy.checkProxyAuthResult( - PROXY_AUTH_REQUEST_SECRET, + PROXY_AUTH_REQUEST_SECRET(), session ); @@ -88,7 +89,7 @@ const secure_axios = async () => { }, }); cors.useAxiosCors(axios, { - apikey: process.env.GRIDA_FIRST_PARTY_CORS_API_KEY, + apikey: process.env.PUBLIC_GRIDA_FIRST_PARTY_CORS_API_KEY, }); return axios; }; diff --git a/cli/auth/login.ts b/cli/auth/login.ts index 246fee8f..1b1caf4c 100644 --- a/cli/auth/login.ts +++ b/cli/auth/login.ts @@ -27,6 +27,7 @@ export async function login() { url = authUrl; await open(authUrl); } catch (e) { + throw new Error("Error while starting authentication session"); exit(1); } diff --git a/cli/bin.ts b/cli/bin.ts index b92bd72d..493a3679 100644 --- a/cli/bin.ts +++ b/cli/bin.ts @@ -73,7 +73,7 @@ export default async function cli() { async () => { login(); }, - [loadenv] + [] ) .command( "logout", @@ -82,7 +82,7 @@ export default async function cli() { async () => { logout(); }, - [loadenv] + [] ) .command( "code [framework] ", diff --git a/cli/index.ts b/cli/index.ts index a1ee225c..c312cbf3 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -3,21 +3,28 @@ import cli from "./bin"; import chalk from "chalk"; export type { GridaConfig } from "./config"; +import dotenv from "dotenv"; +import path from "path"; -process - .on("SIGINT", () => { - process.exit(0); // now the "exit" event will fire - }) - .on("uncaughtException", (err) => { - console.log(chalk.bgRed(err.message ?? "")); - process.exit(1); - }) - .on("unhandledRejection", (err: Error, p) => { - console.error(chalk.bgRed(err.message ?? "")); - process.exit(1); - }); +// process +// .on("SIGINT", () => { +// process.exit(0); // now the "exit" event will fire +// }) +// .on("uncaughtException", (err) => { +// console.log(chalk.bgRed(err.message ?? err)); +// process.exit(1); +// }) +// .on("unhandledRejection", (err: Error, p) => { +// console.error(chalk.bgRed(err.message ?? err)); +// process.exit(1); +// }); // if main if (require.main === module) { + // load env for accessing grida services + dotenv.config({ + path: path.join(__dirname, ".public-credentials", ".env"), + }); + cli(); } diff --git a/cli/package.json b/cli/package.json index a6e700b2..ffbfaf3f 100644 --- a/cli/package.json +++ b/cli/package.json @@ -29,7 +29,8 @@ "grida": "yarn dev", "dev:watch": "ts-node-dev index.ts --watch", "test": "jest", - "build": "ncc build index.ts -o dist -e keytar -e glob -e dotenv", + "copy-env": "node scripts/copy-env.js", + "build": "ncc build index.ts -o dist -e keytar -e glob -e dotenv && yarn copy-env", "prepack": "yarn test && yarn clean && yarn build" }, "devDependencies": { @@ -39,6 +40,7 @@ "@types/which": "^2.0.1", "@types/yargs": "^17.0.3", "@vercel/ncc": "^0.34.0", + "fs-extra": "^10.1.0", "jest": "^28.1.3", "ts-jest": "^28.0.7", "ts-node": "^10.9.1", @@ -49,11 +51,11 @@ "grida": "./dist/index.js" }, "files": [ - "dist", "README.md", - "LICENSE" + "LICENSE", + "dist" ], "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/cli/scripts/copy-env.js b/cli/scripts/copy-env.js new file mode 100644 index 00000000..5df0c43d --- /dev/null +++ b/cli/scripts/copy-env.js @@ -0,0 +1,25 @@ +// copy local .public-credentials under /dist after bundling +// see package.json#scripts#copy-env + +const fs = require("fs-extra"); +const path = require("path"); + +const dist = path.resolve(__dirname, "../dist"); +const publicCredentials = path.resolve(__dirname, "../.public-credentials"); +const distPublicCredentials = path.resolve(dist, ".public-credentials"); + +// make .public-credentials dir under dist +fs.mkdirSync(path.resolve(dist, ".public-credentials")); + +// copy entire public-credentials folder to dist +fs.copySync(publicCredentials, distPublicCredentials); + +// ensure .env exists in dist +try { + fs.ensureFileSync(path.resolve(distPublicCredentials, ".env")); +} catch (e) { + console.error( + "Oops. you cannot run copy-env unless you are maintainer of this project." + ); + throw e; +} diff --git a/cli/tsconfig.json b/cli/tsconfig.json index 8cc3a0ee..3f73fe4b 100644 --- a/cli/tsconfig.json +++ b/cli/tsconfig.json @@ -8,5 +8,5 @@ "esModuleInterop": true, "moduleResolution": "node" }, - "exclude": ["dist", "node_modules", "**/*.spec.ts", "__test__"] + "exclude": ["dist", "node_modules", "**/*.spec.ts", "__test__", "scripts"] } diff --git a/cli/yarn.lock b/cli/yarn.lock index 47fef2b6..98737371 100644 --- a/cli/yarn.lock +++ b/cli/yarn.lock @@ -1374,6 +1374,15 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs-extra@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1449,7 +1458,7 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -graceful-fs@^4.2.9: +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== @@ -2028,6 +2037,15 @@ json5@^2.2.1: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + keytar@^7.9.0: version "7.9.0" resolved "https://registry.yarnpkg.com/keytar/-/keytar-7.9.0.tgz#4c6225708f51b50cbf77c5aae81721964c2918cb" @@ -2805,6 +2823,11 @@ typescript@^4.7.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + update-browserslist-db@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38" From a8dd2db2b9432a4f72263d9f9781f3e02065f5e5 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 16 Aug 2022 04:17:29 +0900 Subject: [PATCH 18/25] v0.0.19 --- cli/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/package.json b/cli/package.json index ffbfaf3f..4453c661 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "grida", - "version": "0.0.18", + "version": "0.0.19", "private": false, "license": "Apache-2.0", "description": "grida CLI", @@ -58,4 +58,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} From 18520df3687f35874ae6a534430fc5e73735480f Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 20 Aug 2022 16:48:53 +0900 Subject: [PATCH 19/25] 0.0.20 hotfix --- cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/package.json b/cli/package.json index 4453c661..c6612b67 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "grida", - "version": "0.0.19", + "version": "0.0.20", "private": false, "license": "Apache-2.0", "description": "grida CLI", From f2f37d230a9643aea72c0d65ecc55e2847acc723 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 30 Aug 2022 04:40:43 +0900 Subject: [PATCH 20/25] add runtime env loader --- cli/.runtime-env/.env | 1 + cli/.runtime-env/.gitignore | 1 + cli/.runtime-env/readme.md | 18 ++++++++++++++++++ cli/index.ts | 7 +++++++ 4 files changed, 27 insertions(+) create mode 100644 cli/.runtime-env/.env create mode 100644 cli/.runtime-env/.gitignore create mode 100644 cli/.runtime-env/readme.md diff --git a/cli/.runtime-env/.env b/cli/.runtime-env/.env new file mode 100644 index 00000000..995fca4a --- /dev/null +++ b/cli/.runtime-env/.env @@ -0,0 +1 @@ +NODE_ENV=production \ No newline at end of file diff --git a/cli/.runtime-env/.gitignore b/cli/.runtime-env/.gitignore new file mode 100644 index 00000000..1e18f275 --- /dev/null +++ b/cli/.runtime-env/.gitignore @@ -0,0 +1 @@ +!.env \ No newline at end of file diff --git a/cli/.runtime-env/readme.md b/cli/.runtime-env/readme.md new file mode 100644 index 00000000..e51aac86 --- /dev/null +++ b/cli/.runtime-env/readme.md @@ -0,0 +1,18 @@ +# this directory is for explicit .env for settings `NODE_ENV` for ncc build + +Since the ncc does not opt us to set runtime env, so we'll need to load & set the env manually. + +```ts +import dotenv from "dotenv"; +dotenv.load({ + path: "./.runtime-env/.env", +}); +``` + +## Note for contributors + +Is this required?: + +Not essential, but some of our modules use logging conditioning based on `NODE_ENV !== "production"` not `NODE_ENV === "development"`. + +So in most case, this will not change the core engine's logic behind, this is for disable verbose logging at this point. diff --git a/cli/index.ts b/cli/index.ts index c312cbf3..4b5acca9 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -26,5 +26,12 @@ if (require.main === module) { path: path.join(__dirname, ".public-credentials", ".env"), }); + /** + * load env for production @see {@link /cli/.runtime-env/readme.md} + */ + dotenv.config({ + path: path.join(__dirname, ".runtime-env", ".env"), + }); + cli(); } From 68169b7f5b2fb8578ebf27529424d02440e225fd Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 30 Aug 2022 04:47:46 +0900 Subject: [PATCH 21/25] fix .env syncer --- cli/package.json | 2 +- cli/scripts/copy-env.js | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/cli/package.json b/cli/package.json index c6612b67..4612b5c6 100644 --- a/cli/package.json +++ b/cli/package.json @@ -58,4 +58,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/cli/scripts/copy-env.js b/cli/scripts/copy-env.js index 5df0c43d..c67fbcb3 100644 --- a/cli/scripts/copy-env.js +++ b/cli/scripts/copy-env.js @@ -5,18 +5,23 @@ const fs = require("fs-extra"); const path = require("path"); const dist = path.resolve(__dirname, "../dist"); -const publicCredentials = path.resolve(__dirname, "../.public-credentials"); -const distPublicCredentials = path.resolve(dist, ".public-credentials"); -// make .public-credentials dir under dist -fs.mkdirSync(path.resolve(dist, ".public-credentials")); - -// copy entire public-credentials folder to dist -fs.copySync(publicCredentials, distPublicCredentials); +function sync_target(target) { + const to = path.resolve(__dirname, `../${target}`); + const tt = path.resolve(dist, target); + // make (e.g. .public-credentials) dir under dist + fs.mkdirSync(path.resolve(dist, target)); + // copy entire (e.g. public-credentials) folder to dist + fs.copySync(to, tt); + // ensure .env exists in dist + fs.ensureFileSync(path.resolve(tt, ".env")); +} +const _public_credentials = ".public-credentials"; +const _runtime_env = ".runtime-env"; -// ensure .env exists in dist try { - fs.ensureFileSync(path.resolve(distPublicCredentials, ".env")); + sync_target(_public_credentials); + sync_target(_runtime_env); } catch (e) { console.error( "Oops. you cannot run copy-env unless you are maintainer of this project." From 88a7138ba4f6b7b572536da19f638b84eb5a990c Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 30 Aug 2022 04:48:46 +0900 Subject: [PATCH 22/25] v0.0.21 --- cli/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/package.json b/cli/package.json index 4612b5c6..f15c12fb 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "grida", - "version": "0.0.20", + "version": "0.0.21", "private": false, "license": "Apache-2.0", "description": "grida CLI", @@ -58,4 +58,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} From 586caff31a7b4895cd88a3345a9c35f6ccb29501 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 12 Sep 2022 08:30:28 +0900 Subject: [PATCH 23/25] update .env seeding line format --- cli/init/init-.env.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/init/init-.env.ts b/cli/init/init-.env.ts index 309b1404..69fec84c 100644 --- a/cli/init/init-.env.ts +++ b/cli/init/init-.env.ts @@ -38,7 +38,9 @@ export function addDotEnv( const dotenv_content = fs.readFileSync(dotenv_file, "utf8"); const dotenv_lines = dotenv_content.split("\n"); const keys = dotenv_lines.map((l) => l.split("=")[0].trim()); - const linetoadd = `${key}=${value}`; + // e.g + // FIGMA_PERSONAL_ACCESS_TOKEN="figd_YBXD5BQ6jle_qhG_fr_lxxxxxxxxxxxxxxxx" + const linetoadd = `${key}="${value}"`; if (keys.some((k) => k === key)) { // key already exists if (allowOverwrite) { From 0aca4638ffefd2826b33608a77d107cf94999ff5 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 24 Sep 2022 02:22:38 +0900 Subject: [PATCH 24/25] update npm keywords --- cli/package.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cli/package.json b/cli/package.json index f15c12fb..9e2d31a6 100644 --- a/cli/package.json +++ b/cli/package.json @@ -4,6 +4,20 @@ "private": false, "license": "Apache-2.0", "description": "grida CLI", + "keywords": [ + "grida", + "cli", + "figma", + "design ci", + "figma cli", + "design tokens", + "design system", + "export", + "icons", + "typography", + "components", + "variants" + ], "homepage": "https://grida.co/cli", "repository": "https://github.com/gridaco/code", "dependencies": { @@ -58,4 +72,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file From 230c3030ab486c3cbb4e24843df9876a3894724b Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Sat, 24 Sep 2022 02:23:56 +0900 Subject: [PATCH 25/25] v0.0.22 --- cli/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/package.json b/cli/package.json index 9e2d31a6..da1bbf85 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "grida", - "version": "0.0.21", + "version": "0.0.22", "private": false, "license": "Apache-2.0", "description": "grida CLI", @@ -72,4 +72,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +}