├── .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 |
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 |
--------------------------------------------------------------------------------