├── .npmignore ├── w3c.json ├── templates ├── .pr-preview.json ├── LICENSE.md ├── index.bs ├── CONTRIBUTING.md ├── index.html └── README.md ├── README.md ├── theme.mjs ├── .gitignore ├── package.json ├── git.mjs ├── messages.mjs ├── prompts.mjs ├── CHANGELOG.md └── index.mjs /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [80485] 3 | , "contacts": ["marcoscaceres"] 4 | , "repo-type": "tool" 5 | } 6 | -------------------------------------------------------------------------------- /templates/.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "{{srcfile}}", 3 | "type": "{{preprocessor}}", 4 | "params": { 5 | "force": 1 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # starter-kit 2 | 3 | A simple starter kit for [WICG](https://wicg.io) specs. Helps you create a repo and generates some starting files. 4 | 5 | ## Install 6 | 7 | Type the following and follow the prompts: 8 | 9 | ```Bash 10 | npx wicg init "My Awesome API" 11 | ``` 12 | -------------------------------------------------------------------------------- /templates/LICENSE.md: -------------------------------------------------------------------------------- 1 | All Reports in this Repository are licensed by Contributors under the 2 | [W3C Software and Document License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document). 3 | Contributions to Specifications are made under the [W3C CLA](https://www.w3.org/community/about/agreements/cla/). 4 | -------------------------------------------------------------------------------- /theme.mjs: -------------------------------------------------------------------------------- 1 | const chalk = await import("chalk"); 2 | export const b = chalk.default.blue.bind(chalk); 3 | export const g = chalk.default.green.bind(chalk); 4 | export const gr = chalk.default.gray.bind(chalk); 5 | export const m = chalk.default.magenta.bind(chalk); 6 | export const r = chalk.default.red.bind(chalk); 7 | export const y = chalk.default.yellow.bind(chalk); 8 | export const heading = function (text) { 9 | return chalk.default.underline(`\n${text.toUpperCase()}\n`); 10 | }; 11 | -------------------------------------------------------------------------------- /templates/index.bs: -------------------------------------------------------------------------------- 1 |
 2 | Title: {{name}}
 3 | Shortname: {{repo}}
 4 | Level: 1
 5 | Status: CG-DRAFT
 6 | Group: WICG
 7 | Repository: WICG/{{repo}}
 8 | URL: http://example.com/url-this-spec-will-live-at
 9 | Editor: {{userName}}, {{affiliation}} {{affiliationURL}}, {{userEmail}}
10 | !Tests: web-platform-tests {{repo}}/ (ongoing work)
11 | Abstract: A short description of your spec, one or two sentences.
12 | 
13 | 14 | Introduction {#intro} 15 | ===================== 16 | 17 | See https://github.com/tabatkins/bikeshed to get started. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /templates/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # {{name}} 2 | 3 | This repository is being used for work in the W3C {{name}}, governed by the [W3C Community License 4 | Agreement (CLA)](http://www.w3.org/community/about/agreements/cla/). To make substantive contributions, 5 | you must join the CG. 6 | 7 | If you are not the sole contributor to a contribution (pull request), please identify all 8 | contributors in the pull request comment. 9 | 10 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 11 | 12 | ``` 13 | +@github_username 14 | ``` 15 | 16 | If you added a contributor by mistake, you can remove them in a comment with: 17 | 18 | ``` 19 | -@github_username 20 | ``` 21 | 22 | If you are making a pull request on behalf of someone else but you had no part in designing the 23 | feature, you can remove yourself with the above syntax. 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wicg", 3 | "version": "1.2.8", 4 | "description": "Tools to get you started with the WICG", 5 | "scripts": { 6 | "release": "standard-version", 7 | "semantic-release": "semantic-release" 8 | }, 9 | "bin": { 10 | "wicg": "index.mjs" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/WICG/starter-kit.git" 15 | }, 16 | "keywords": [ 17 | "WICG", 18 | "W3C", 19 | "standards" 20 | ], 21 | "author": "Marcos Caceres", 22 | "license": "CC0-1.0", 23 | "bugs": { 24 | "url": "https://github.com/WICG/starter-kit/issues" 25 | }, 26 | "preferGlobal": true, 27 | "engineStrict": true, 28 | "engines": { 29 | "node": ">=16.16.0" 30 | }, 31 | "homepage": "https://github.com/WICG/starter-kit#readme", 32 | "dependencies": { 33 | "chalk": "^5.3.0", 34 | "commander": "^11.1.0", 35 | "prompt": "^1.3.0" 36 | }, 37 | "devDependencies": { 38 | "semantic-release": "^23.0.0", 39 | "standard-version": "^9.5.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{name}} 7 | 8 | 27 | 28 | 29 | 30 |
31 |

32 | This specification does neat stuff. 33 |

34 |
35 |
36 |

37 | This is an unofficial proposal. 38 |

39 |
40 |
41 |

Introduction

42 |

43 | See ReSpec's 44 | user guide for how to get started! 45 |

46 |
47 |
48 |

Start your spec!

49 |
50 |     interface Foo {
51 |       attribute Bar bar;
52 |       void doTheFoo();
53 |     };
54 |     
55 |

56 | See ReSpec's 57 | WebIDL guide for how to write [[WebIDL]] APIs! 58 |

59 |

60 | The doTheFoo method. 61 |

62 |

63 | The bar attribute. 64 |

65 |
66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /git.mjs: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | import { exec } from "child_process"; 3 | import path from "path"; 4 | 5 | function toExecPromise(cmd, timeout) { 6 | if (!timeout) { 7 | timeout = 60000; 8 | } 9 | return new Promise((resolve, reject) => { 10 | const id = setTimeout(() => { 11 | reject(new Error(`Command took too long: ${cmd}`)); 12 | proc.kill("SIGTERM"); 13 | }, timeout); 14 | const proc = exec(cmd, (err, stdout) => { 15 | clearTimeout(id); 16 | if (err) { 17 | return reject(err); 18 | } 19 | resolve(stdout); 20 | }); 21 | }); 22 | } 23 | 24 | export function git(cmd) { 25 | return toExecPromise(`git ${cmd}`); 26 | } 27 | 28 | git.getCurrentBranch = async () => { 29 | const branch = await git(`rev-parse --abbrev-ref HEAD`); 30 | return branch.trim(); 31 | }; 32 | 33 | git.getConfigData = async (configItem) => { 34 | let data; 35 | try { 36 | data = await git(configItem); 37 | } catch (err) { 38 | data = ""; 39 | } 40 | return data; 41 | }; 42 | 43 | git.getBranches = async () => { 44 | const rawBranches = await git("branch --no-color"); 45 | const branches = rawBranches 46 | .split("\n") 47 | .map((branch) => branch.replace("*", "").trim()) 48 | .reduce((collector, branch) => collector.add(branch), new Set()); 49 | return Array.from(branches); 50 | }; 51 | 52 | git.hasBranch = async (branch) => { 53 | const branches = await git.getBranches(); 54 | return branches.includes(branch); 55 | }; 56 | 57 | git.switchBranch = async (branch) => { 58 | const hasBranch = await git.hasBranch(branch); 59 | if (!hasBranch) { 60 | await git(`checkout -b ${branch}`); 61 | } else { 62 | await git(`checkout ${branch}`); 63 | } 64 | }; 65 | 66 | git.getRepoName = async () => { 67 | const name = await git("rev-parse --show-toplevel"); 68 | return path.basename(name).trim(); 69 | }; 70 | -------------------------------------------------------------------------------- /messages.mjs: -------------------------------------------------------------------------------- 1 | const chalk = await import("chalk"); 2 | const { b, g, gr, r, y, m } = await import("./theme.mjs"); 3 | 4 | // Shown if everything is successful 5 | export const finished = ` 6 | ${chalk.default.underline("NEXT STEPS")} 7 | 8 | Congrats! You are ready to start. Please push everything up to GitHub 9 | when you are ready. 10 | 11 | Please review the files that were just added to this directory. 12 | 13 | If you are new to spec writing or the WICG, we strongly encourage you to read: 14 | 15 | ⭐ Contributing New Proposals: 16 | ${b("https://github.com/WICG/admin#contributing-new-proposals")} 17 | 18 | ⭐️ API Design Principles: 19 | ${b("https://w3ctag.github.io/design-principles/")} 20 | 21 | ⭐️ Writing Promise-Using Specs: 22 | ${b("http://www.w3.org/2001/tag/doc/promises-guide")} 23 | 24 | Good luck! 🐼 25 | `; 26 | 27 | const wicgURL = chalk.default.blue.underline.bold("https//wicg.io"); 28 | const wicgTitle = chalk.default.yellow("Web Incubator Community Group"); 29 | const W3C = `${gr(">--=")} ${b("W")} * ${gr("3")} * ${b("C")} ${gr("=--<")}`; 30 | export const logo = ` 31 | ${y(" __ __")}${r(".___")}${m("_________")}${g(" ________")} ${W3C} 32 | ${y("/ \\ / \\")}${r(" \\")}${m("_ ___ \\")}${g(" / _____/")} 33 | ${y("\\ \\/\\/ /")}${r(" /")}${m(" \\ \\/")}${g("/ \\ ___")} ${wicgTitle} 34 | ${y(" \\ /")}${r("| \\")}${m(" \\___")}${g("\\ \\_\\ \\")} 35 | ${y(" \\__/\\ /")}${r(" |___|")}${m("\\______ /")}${g("\\______ /")} ${wicgURL} 36 | ${y(" \\/")} ${m("\\/")} ${g("\\/")} 37 | 38 | This utility creates the basic files you need to get started. 39 | It guesses sensible defaults based on your git setup. 40 | 41 | Press ^C at any time to quit. 42 | `; 43 | 44 | export const example = ` 45 | ℹ️ A utility to get you started writing WICG specs. 46 | 47 | Example: 48 | 49 | wicg init "My Awesome API" 50 | 51 | More info at: ${b("https://wicg.io")} | bugs: ${b("https://github.com/WICG/starter-kit")} 52 | `; 53 | -------------------------------------------------------------------------------- /prompts.mjs: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | import { git } from "./git.mjs"; 3 | import path from "path"; 4 | import prompt from "prompt"; 5 | 6 | // Configure prompt 7 | prompt.message = " 👉 "; 8 | prompt.delimiter = ""; 9 | 10 | // Utility function to convert first letter to uppercase. 11 | function upperCaseFirstLetter(word) { 12 | if (typeof word !== "string") { 13 | throw new TypeError("Expected string"); 14 | } 15 | if (!word) { 16 | return word; 17 | } 18 | return word.charAt(0).toUpperCase() + word.slice(1); 19 | } 20 | 21 | // User prompt tasks 22 | export const Prompts = { 23 | askQuestion(promptOps) { 24 | return new Promise((resolve, reject) => { 25 | prompt.get(promptOps, (err, res) => { 26 | if (err) { 27 | return reject(new Error(" 🙅 User canceled.")); 28 | } 29 | resolve(res.question); 30 | }); 31 | }); 32 | }, 33 | askRepoName() { 34 | const promptOps = { 35 | description: "Name of Git repository:", 36 | default: path.basename(process.cwd()), 37 | type: "string", 38 | before(value) { 39 | return value.trim(); 40 | }, 41 | }; 42 | return this.askQuestion(promptOps); 43 | }, 44 | askProjectName(repo) { 45 | const promptOps = { 46 | description: "Name of project:", 47 | default: `The ${upperCaseFirstLetter(repo)} API`, 48 | type: "string", 49 | before(value) { 50 | return value.trim(); 51 | }, 52 | }; 53 | return this.askQuestion(promptOps); 54 | }, 55 | async askUserName() { 56 | const user = await git.getConfigData("config user.name"); 57 | const promptOps = { 58 | description: "Name of Primary Editor of the spec:", 59 | default: user.trim(), 60 | type: "string", 61 | before(value) { 62 | return value.trim(); 63 | }, 64 | }; 65 | return this.askQuestion(promptOps); 66 | }, 67 | askAffiliation(hint = "") { 68 | const promptOps = { 69 | description: `Company affiliation(e.g., ${ 70 | upperCaseFirstLetter(hint) || "Monsters" 71 | } Inc.):`, 72 | default: upperCaseFirstLetter(hint), 73 | type: "string", 74 | before(value) { 75 | return value.trim(); 76 | }, 77 | }; 78 | return this.askQuestion(promptOps); 79 | }, 80 | askAffiliationURL(emailHint = "") { 81 | const [, hint] = emailHint.match(/(?:@)(.+)/); 82 | const promptOps = { 83 | description: "Company URL:", 84 | type: "string", 85 | before(value) { 86 | return value.trim(); 87 | }, 88 | }; 89 | if (hint) { 90 | promptOps.default = `https://${hint}`; 91 | } 92 | return this.askQuestion(promptOps); 93 | }, 94 | async askEmail() { 95 | const email = await git.getConfigData("config user.email"); 96 | const promptOps = { 97 | description: "Email (optional):", 98 | default: email.trim(), 99 | type: "string", 100 | }; 101 | return this.askQuestion(promptOps); 102 | }, 103 | askWhichGitBranch() { 104 | const promptOps = { 105 | description: "Main git branch for the spec:", 106 | default: "main", 107 | pattern: /^[\w\-]+$/, 108 | type: "string", 109 | message: "Name must be only letters and dashes", 110 | before(value) { 111 | return value.trim(); 112 | }, 113 | }; 114 | return this.askQuestion(promptOps); 115 | }, 116 | askWhichPreProcessor() { 117 | const promptOps = { 118 | description: "Spec preprocessor (respec or bikeshed):", 119 | default: "respec", 120 | type: "string", 121 | pattern: /^(respec|bikeshed|bs)$/i, 122 | before(value) { 123 | return value.trim().toLowerCase(); 124 | }, 125 | }; 126 | return this.askQuestion(promptOps); 127 | }, 128 | }; 129 | -------------------------------------------------------------------------------- /templates/README.md: -------------------------------------------------------------------------------- 1 | # {{name}} explainer 2 | 3 | This is the repository for {{name}}. You're welcome to 4 | [contribute](CONTRIBUTING.md)! 5 | 6 | To fill this out, please see: https://github.com/w3ctag/w3ctag.github.io/blob/master/explainers.md 7 | ## Authors: 8 | 9 | - [Author 1] 10 | - [Author 2] 11 | - [etc.] 12 | 13 | ## Participate 14 | - [Issue tracker] 15 | - [Discussion forum] 16 | 17 | ## Table of Contents [if the explainer is longer than one printed page] 18 | 19 | [You can generate a Table of Contents for markdown documents using a tool like [doctoc](https://github.com/thlorenz/doctoc).] 20 | 21 | 22 | 23 | 24 | ## Introduction 25 | 26 | [The "executive summary" or "abstract". 27 | Explain in a few sentences what the goals of the project are, 28 | and a brief overview of how the solution works. 29 | This should be no more than 1-2 paragraphs.] 30 | 31 | ## Goals [or Motivating Use Cases, or Scenarios] 32 | 33 | [What is the **end-user need** which this project aims to address?] 34 | 35 | ## Non-goals 36 | 37 | [If there are "adjacent" goals which may appear to be in scope but aren't, 38 | enumerate them here. This section may be fleshed out as your design progresses and you encounter necessary technical and other trade-offs.] 39 | 40 | ## [API 1] 41 | 42 | [For each related element of the proposed solution - be it an additional JS method, a new object, a new element, a new concept etc., create a section which briefly describes it.] 43 | 44 | ```js 45 | // Provide example code - not IDL - demonstrating the design of the feature. 46 | 47 | // If this API can be used on its own to address a user need, 48 | // link it back to one of the scenarios in the goals section. 49 | 50 | // If you need to show how to get the feature set up 51 | // (initialized, or using permissions, etc.), include that too. 52 | ``` 53 | 54 | [Where necessary, provide links to longer explanations of the relevant pre-existing concepts and API. 55 | If there is no suitable external documentation, you might like to provide supplementary information as an appendix in this document, and provide an internal link where appropriate.] 56 | 57 | [If this is already specced, link to the relevant section of the spec.] 58 | 59 | [If spec work is in progress, link to the PR or draft of the spec.] 60 | 61 | ## [API 2] 62 | 63 | [etc.] 64 | 65 | ## Key scenarios 66 | 67 | [If there are a suite of interacting APIs, show how they work together to solve the key scenarios described.] 68 | 69 | ### Scenario 1 70 | 71 | [Description of the end-user scenario] 72 | 73 | ```js 74 | // Sample code demonstrating how to use these APIs to address that scenario. 75 | ``` 76 | 77 | ### Scenario 2 78 | 79 | [etc.] 80 | 81 | ## Detailed design discussion 82 | 83 | ### [Tricky design choice #1] 84 | 85 | [Talk through the tradeoffs in coming to the specific design point you want to make.] 86 | 87 | ```js 88 | // Illustrated with example code. 89 | ``` 90 | 91 | [This may be an open question, 92 | in which case you should link to any active discussion threads.] 93 | 94 | ### [Tricky design choice 2] 95 | 96 | [etc.] 97 | 98 | ## Considered alternatives 99 | 100 | [This should include as many alternatives as you can, 101 | from high level architectural decisions down to alternative naming choices.] 102 | 103 | ### [Alternative 1] 104 | 105 | [Describe an alternative which was considered, 106 | and why you decided against it.] 107 | 108 | ### [Alternative 2] 109 | 110 | [etc.] 111 | 112 | ## Stakeholder Feedback / Opposition 113 | 114 | [Implementors and other stakeholders may already have publicly stated positions on this work. If you can, list them here with links to evidence as appropriate.] 115 | 116 | - [Implementor A] : Positive 117 | - [Stakeholder B] : No signals 118 | - [Implementor C] : Negative 119 | 120 | [If appropriate, explain the reasons given by other implementors for their concerns.] 121 | 122 | ## References & acknowledgements 123 | 124 | [Your design will change and be informed by many people; acknowledge them in an ongoing way! It helps build community and, as we only get by through the contributions of many, is only fair.] 125 | 126 | [Unless you have a specific reason not to, these should be in alphabetical order.] 127 | 128 | Many thanks for valuable feedback and advice from: 129 | 130 | - [Person 1] 131 | - [Person 2] 132 | - [etc.] 133 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [1.2.8](https://github.com/WICG/starter-kit/compare/v1.2.6...v1.2.8) (2024-01-24) 6 | 7 | ### [1.2.7](https://github.com/WICG/starter-kit/compare/v1.2.6...v1.2.7) (2022-07-27) 8 | 9 | ### [1.2.6](https://github.com/WICG/starter-kit/compare/v1.2.5...v1.2.6) (2022-01-18) 10 | 11 | ### [1.2.5](https://github.com/WICG/starter-kit/compare/v1.2.1...v1.2.5) (2021-09-21) 12 | 13 | 14 | ### Bug Fixes 15 | 16 | * **package:** update chalk to version 2.0.0 ([#9](https://github.com/WICG/starter-kit/issues/9)) ([d86d6ca](https://github.com/WICG/starter-kit/commit/d86d6cad9e0f462fec627610c3fdc887582da602)) 17 | * **package:** update chalk to version 3.0.0 ([#46](https://github.com/WICG/starter-kit/issues/46)) ([dc0854a](https://github.com/WICG/starter-kit/commit/dc0854a3923b4cf676036f0f2d1e7b415ac1dcc9)) 18 | * **package:** update chalk to version 4.0.0 ([#53](https://github.com/WICG/starter-kit/issues/53)) ([262b8b5](https://github.com/WICG/starter-kit/commit/262b8b5fbba625aa45ecd207b103e89b4c5359ed)) 19 | * **package:** update commander to version 3.0.0 ([#44](https://github.com/WICG/starter-kit/issues/44)) ([dab9eeb](https://github.com/WICG/starter-kit/commit/dab9eebc0187bf11b1cc940e37ab3cb7420dd6c4)) 20 | * **package:** update commander to version 4.0.0 ([#45](https://github.com/WICG/starter-kit/issues/45)) ([03a9f08](https://github.com/WICG/starter-kit/commit/03a9f084e120cf245bc7881070d2530e2f18fd85)) 21 | * **package:** update commander to version 5.0.0 ([#51](https://github.com/WICG/starter-kit/issues/51)) ([b0ba179](https://github.com/WICG/starter-kit/commit/b0ba179f8778eb0551193c6f3b99b5b96e4756f7)) 22 | 23 | ### [1.2.3](https://github.com/WICG/starter-kit/compare/v1.2.1...v1.2.3) (2021-09-21) 24 | 25 | 26 | ### Bug Fixes 27 | 28 | * **package:** update chalk to version 2.0.0 ([#9](https://github.com/WICG/starter-kit/issues/9)) ([d86d6ca](https://github.com/WICG/starter-kit/commit/d86d6cad9e0f462fec627610c3fdc887582da602)) 29 | * **package:** update chalk to version 3.0.0 ([#46](https://github.com/WICG/starter-kit/issues/46)) ([dc0854a](https://github.com/WICG/starter-kit/commit/dc0854a3923b4cf676036f0f2d1e7b415ac1dcc9)) 30 | * **package:** update chalk to version 4.0.0 ([#53](https://github.com/WICG/starter-kit/issues/53)) ([262b8b5](https://github.com/WICG/starter-kit/commit/262b8b5fbba625aa45ecd207b103e89b4c5359ed)) 31 | * **package:** update commander to version 3.0.0 ([#44](https://github.com/WICG/starter-kit/issues/44)) ([dab9eeb](https://github.com/WICG/starter-kit/commit/dab9eebc0187bf11b1cc940e37ab3cb7420dd6c4)) 32 | * **package:** update commander to version 4.0.0 ([#45](https://github.com/WICG/starter-kit/issues/45)) ([03a9f08](https://github.com/WICG/starter-kit/commit/03a9f084e120cf245bc7881070d2530e2f18fd85)) 33 | * **package:** update commander to version 5.0.0 ([#51](https://github.com/WICG/starter-kit/issues/51)) ([b0ba179](https://github.com/WICG/starter-kit/commit/b0ba179f8778eb0551193c6f3b99b5b96e4756f7)) 34 | 35 | 36 | ## [1.2.1](https://github.com/WICG/starter-kit/compare/v1.2.0...v1.2.1) (2017-05-01) 37 | 38 | 39 | ### Bug Fixes 40 | 41 | * **index:** forgot to pass data around ([9b7b8c0](https://github.com/WICG/starter-kit/commit/9b7b8c0)) 42 | 43 | 44 | 45 | 46 | # [1.2.0](https://github.com/WICG/starter-kit/compare/v1.1.1...v1.2.0) (2017-05-01) 47 | 48 | 49 | ### Bug Fixes 50 | 51 | * **index:** make init msg friendlier ([5b85bc5](https://github.com/WICG/starter-kit/commit/5b85bc5)) 52 | * **index.bs:** replace issue tracking (closes [#1](https://github.com/WICG/starter-kit/issues/1)) ([#2](https://github.com/WICG/starter-kit/issues/2)) ([fbcda30](https://github.com/WICG/starter-kit/commit/fbcda30)) 53 | 54 | 55 | ### Features 56 | 57 | * **templats/.pr-preview:** add ReSpec support ([#8](https://github.com/WICG/starter-kit/issues/8)) ([815cbd0](https://github.com/WICG/starter-kit/commit/815cbd0)) 58 | 59 | 60 | 61 | 62 | ## [1.1.1](https://github.com/WICG/starter-kit/compare/v1.1.0...v1.1.1) (2016-08-24) 63 | 64 | 65 | 66 | 67 | # [1.1.0](https://github.com/WICG/starter-kit/compare/v1.0.0...v1.1.0) (2016-08-24) 68 | 69 | 70 | ### Features 71 | 72 | * add bikeshed template ([5e1044e](https://github.com/WICG/starter-kit/commit/5e1044e)) 73 | 74 | 75 | 76 | 77 | # [1.0.0](https://github.com/WICG/starter-kit/compare/v1.0.0-beta.1...v1.0.0) (2016-08-23) 78 | 79 | 80 | ### Features 81 | 82 | * **git:** teach git more common tasks ([e1fcad6](https://github.com/WICG/starter-kit/commit/e1fcad6)) 83 | * **index.html:** improve ReSpec template ([4604fff](https://github.com/WICG/starter-kit/commit/4604fff)) 84 | * **README:** Link to contributing file ([b0e745a](https://github.com/WICG/starter-kit/commit/b0e745a)) 85 | -------------------------------------------------------------------------------- /index.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { promises as fs } from "fs"; 4 | import { git } from "./git.mjs"; 5 | import { finished, logo, example } from "./messages.mjs"; 6 | import path from "path"; 7 | import { program } from "commander"; 8 | import { Prompts } from "./prompts.mjs"; 9 | import pkg from "./package.json" with { type: "json" }; 10 | import { fileURLToPath } from "url"; 11 | const __filename = fileURLToPath(import.meta.url); 12 | const __dirname = path.dirname(__filename); 13 | const version = pkg.version; 14 | const tmplDir = __dirname + "/templates/"; 15 | 16 | // Colors 17 | const { g, gr, r, y, heading } = await import("./theme.mjs"); 18 | const chk = g("✔"); 19 | 20 | async function performGitTasks(collectedData) { 21 | console.info(heading("Performing git tasks")); 22 | let newRepo = ""; 23 | if (collectedData.repo !== path.basename(process.cwd())) { 24 | newRepo = collectedData.repo; 25 | } 26 | if (collectedData.needsGitInit) { 27 | const result = await git(`init ${newRepo}`); 28 | if (newRepo) { 29 | process.chdir(`${process.cwd()}/${newRepo}`); 30 | } 31 | console.info(g(` ${chk} ${result.trim()}`)); 32 | } 33 | await git.switchBranch(collectedData.mainBranch); 34 | console.info(g(` ${chk} switched to branch ${collectedData.mainBranch}`)); 35 | } 36 | 37 | function populateTemplate(rawData, collectedData, file) { 38 | // find all {{\w}} and replace them form collectedData 39 | const replaceSet = (rawData.match(/{{\w+}}/gm) || []) 40 | .map((match) => match.replace(/[{{|}}]/g, "")) 41 | .reduce((collector, match) => collector.add(match), new Set()); 42 | return Array.from(replaceSet) 43 | .map((match) => { 44 | const key = new RegExp(`{{${match}}}`, "gm"); 45 | if (!collectedData[match]) { 46 | console.warn( 47 | `${y("Warning")}: no match for \`${match}\` in template ${file}` 48 | ); 49 | } 50 | const value = collectedData[match] || match; 51 | return [key, value]; 52 | }) 53 | .reduce((rawData, [key, value]) => rawData.replace(key, value), rawData); 54 | } 55 | 56 | async function getFilesToInclude(collectedData) { 57 | const excludedFiles = new Set(); 58 | switch (collectedData.preprocessor) { 59 | case "bikeshed": 60 | excludedFiles.add("index.html"); 61 | break; 62 | case "respec": 63 | excludedFiles.add("index.bs"); 64 | break; 65 | } 66 | const dirFiles = await fs.readdir(tmplDir); 67 | return dirFiles 68 | .filter((filename) => !excludedFiles.has(filename)) 69 | .map((filename) => [tmplDir + filename, `${process.cwd()}/${filename}`]); 70 | } 71 | 72 | async function fileExists(filePath) { 73 | try { 74 | await fs.access(filePath, fs.F_OK); 75 | } catch (err) { 76 | return false; 77 | } 78 | return true; 79 | } 80 | 81 | // Uses git to get the name of the repo (cwd) 82 | async function writeTemplates(collectedData) { 83 | console.info(heading("Creating Templates")); 84 | const destinations = await getFilesToInclude(collectedData); 85 | const successfulWrites = []; 86 | for (let [from, to] of destinations) { 87 | if (await fileExists(to)) { 88 | console.warn( 89 | `${y(" ⚠️ skipping")} ${gr(path.basename(to))} (already exists)` 90 | ); 91 | continue; 92 | } 93 | const rawData = await fs.readFile(from, "utf8"); 94 | const data = populateTemplate(rawData, collectedData, path.basename(from)); 95 | try { 96 | await fs.writeFile(to, data); 97 | const basename = path.basename(to); 98 | console.log(` ${chk} ${g("created")} ${gr(basename)}`); 99 | successfulWrites.push(basename); 100 | } catch (err) { 101 | console.error( 102 | ` 💥 ${r("error: ")} could not create ${gr(path.basename(to))}` 103 | ); 104 | } 105 | } 106 | if (successfulWrites.length) { 107 | await git(`add ${successfulWrites.join(" ")}`); 108 | await git(`commit -am "feat: add WICG files."`); 109 | console.info( 110 | g(`\nCommitted changes to "${collectedData.mainBranch}" branch.`) 111 | ); 112 | } 113 | return collectedData; 114 | } 115 | 116 | // Tell the user what they should do next. 117 | function postInitialization() { 118 | console.info(finished); 119 | } 120 | 121 | async function collectProjectData(name = "") { 122 | console.info(heading("Let's get you set up! (About this WICG project)")); 123 | let repo = ""; 124 | let needsGitInit = true; 125 | try { 126 | repo = await git.getRepoName(); 127 | needsGitInit = false; 128 | } catch (err) { 129 | const response = await Prompts.askRepoName(); 130 | repo = response.trim(); 131 | } 132 | // Let's get the name of the project 133 | if (!name) { 134 | name = await Prompts.askProjectName(repo); 135 | } 136 | // Derive the user's name from git config 137 | const userName = await Prompts.askUserName(); 138 | const userEmail = await Prompts.askEmail(); 139 | // Get the company from the email 140 | const [, affiliationHint] = /(?:@)([\w|-]+)/.exec(userEmail); 141 | const affiliation = await Prompts.askAffiliation(affiliationHint); 142 | let affiliationURL = ""; 143 | if (affiliation) { 144 | affiliationURL = await Prompts.askAffiliationURL(userEmail); 145 | } 146 | const mainBranch = await Prompts.askWhichGitBranch(); 147 | const preprocessor = await Prompts.askWhichPreProcessor(); 148 | return { 149 | affiliation, 150 | affiliationURL, 151 | mainBranch, 152 | name, 153 | needsGitInit, 154 | preprocessor, 155 | repo, 156 | srcfile: preprocessor === "bikeshed" ? "index.bs" : "index.html", 157 | userEmail, 158 | userName, 159 | }; 160 | } 161 | 162 | program 163 | .version(version) 164 | .command("init [name]") 165 | .description("start a new incubation project") 166 | .action(async (name, options) => { 167 | console.info(logo); 168 | try { 169 | const collectedData = await collectProjectData(name, options); 170 | await performGitTasks(collectedData); 171 | await writeTemplates(collectedData); 172 | } catch (err) { 173 | console.error(`\n 💥 ${r(err.message)}`, err); 174 | } 175 | postInitialization(); 176 | }); 177 | 178 | program.parse(process.argv); 179 | 180 | if (!process.argv.slice(2).length) { 181 | program.outputHelp(); 182 | console.log(example); 183 | } 184 | --------------------------------------------------------------------------------