Skip to content

Commit

Permalink
Merge pull request #15 from jspsych/reorganization
Browse files Browse the repository at this point in the history
Release new-timeline for testing on jspsych-timelines repo
  • Loading branch information
cherriechang authored Jan 20, 2025
2 parents 094f3a6 + dbf39bf commit a67b375
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 3,091 deletions.
5 changes: 5 additions & 0 deletions .changeset/gorgeous-grapes-poke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@jspsych/new-timeline": patch
---

This release publishes the @jspsych/new-timeline package on npm. This is a command line tool for creating jsPsych timelines with provided template code.
3,014 changes: 8 additions & 3,006 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/new-extension/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ async function runPrompts() {
if (!isContrib) {
readmePath = await input({
message: "Enter the path to the README.md file for this extension package [Optional]:",
default: `${destDir}/README.md`,
default: `${destDir}/${name}/README.md`,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ var _globalName_ = (function (jspsych) {
* {description}
*
* @author {author}
* @see {@link {documentation-url}}
* @see {@link {documentationUrl}}
*/
class ExtensionNameExtension {
constructor(jsPsych) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface OnFinishParameters {}
* {description}
*
* @author {author}
* @see {@link {documentation-url}}}
* @see {@link {documentationUrl}}}
*/
class ExtensionNameExtension implements JsPsychExtension {
static info: JsPsychExtensionInfo = {
Expand Down
3 changes: 2 additions & 1 deletion packages/new-plugin/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ async function runPrompts() {
let readmePath = "";
if (!isContrib) {
readmePath = await input({
message: "Enter the path to the README.md file forthis plugin package [Optional]:"
message: "Enter the path to the README.md file for this plugin package [Optional]:",
default: `${destDir}/plugin-${name}/README.md`
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type Info = typeof info;
* {description}
*
* @author {author}
* @see {@link {documentation-url}}}
* @see {@link {documentationUrl}}}
*/
class PluginNamePlugin implements JsPsychPlugin<Info> {
static info = info;
Expand Down
182 changes: 123 additions & 59 deletions packages/new-timeline/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,58 @@ const git = simpleGit();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

function formatName(input) {
async function getRepoRoot() {
try {
const rootDir = await git.revparse(["--show-toplevel"]);
return rootDir;
} catch (error) {
console.error("Not a git repository or no repository root found.");
return "";
}
}

async function getRemoteGitRootUrl() {
try {
const remotes = await git.getRemotes(true);
const originRemote = remotes.find((remote) => remote.name === "origin");
if (originRemote) {
let remoteGitRootUrl = originRemote.refs.fetch;
if (remoteGitRootUrl.startsWith("[email protected]:")) {
remoteGitRootUrl = remoteGitRootUrl.replace("[email protected]:", "git+https://github.com/");
}
return remoteGitRootUrl;
}
console.warn("No remote named 'origin' found.");
return "";
} catch (error) {
console.error("Error getting remote root Git URL:", error);
return "";
}
}

async function getRemoteGitUrl() {
let remoteGitUrl;
const remoteGitRootUrl = await getRemoteGitRootUrl();
const repoRoot = await getRepoRoot();
if (repoRoot) {
const currentDir = process.cwd();
const relativePath = path.relative(repoRoot, currentDir);
if (relativePath) {
remoteGitUrl = `${remoteGitRootUrl}/tree/main/${relativePath}`;
}
return remoteGitUrl;
}
console.warn("No Git repository root found.");
return "";
}

function getGitHttpsUrl(gitUrl) {
gitUrl = gitUrl.replace("git+", "");
gitUrl = gitUrl.replace(".git", "");
return gitUrl;
}

function hyphenateName(input) {
return input
.trim()
.replace(/[\s_]+/g, "-") // Replace all spaces and underscores with hyphens
Expand All @@ -24,37 +75,43 @@ function formatName(input) {
.toLowerCase();
}

async function getRepoRoot() {
try {
const rootDir = await git.revparse(['--show-toplevel']);
return rootDir;
} catch (error) {
console.error("Not a git repository or no repository root found.");
return null;
}
function camelCaseName(input) {
return (
input.charAt(0).toUpperCase() + input.slice(1).replace(/-([a-z])/g, (g) => g[1].toUpperCase())
);
}

async function runPrompts() {
let isGitRepo = await git.checkIsRepo();
let isTimelinesRepo = false;
if (isGitRepo) {
isTimelinesRepo = await git.getRemotes(true).then(remotes => {
return remotes.some(remote => remote.refs.fetch.includes('[email protected]:jspsych/jspsych-timelines.git'));
});
async function getCwdInfo() {
// If current directory is the jspsych-timelines repository
if (await git.checkIsRepo()) {
const remotes = await git.getRemotes(true);
return {
isTimelinesRepo: remotes.some((remote) =>
remote.refs.fetch.includes("[email protected]:jspsych/jspsych-timelines.git")
),
destDir: path.join(await getRepoRoot(), "packages"),
};
}
// If current directory is not the jspsych-timelines repository
else {
return {
isTimelinesRepo: false,
destDir: process.cwd(),
};
}
}

let destDir = isTimelinesRepo ? path.join(await getRepoRoot(), 'packages') : process.cwd();

async function runPrompts(cwdInfo) {
const name = await input({
message: "What do you want to call this timeline package?",
required: true,
transformer: (input) => {
return formatName(input);
return hyphenateName(input);
},
validate: (input) => {
const fullpackageFilename = `${destDir}/timeline-${formatName(input)}`;
if (fs.existsSync(fullpackageFilename)) {
return "A timeline package with this name already exists. Please choose a different name.";
const packagePath = `${cwdInfo.destDir}/timeline-${hyphenateName(input)}`;
if (fs.existsSync(packagePath)) {
return "A timeline package with this name already exists in this directory. Please choose a different name.";
} else {
return true;
}
Expand All @@ -78,70 +135,67 @@ async function runPrompts() {
const language = await select({
message: "What language do you want to use?",
choices: [
{
name: "TypeScript",
value: "ts",
},
{
name: "JavaScript",
value: "js",
}
{ name: "TypeScript", value: "ts" },
{ name: "JavaScript", value: "js" },
],
loop: false,
});

// If not in the jspsych-timelines repository, ask for the path to the README.md file
let readmePath = "";
if (!isTimelinesRepo) {
if (!cwdInfo.isTimelinesRepo) {
readmePath = await input({
message: "Enter the path to the README.md file for this timeline package [Optional]:",
default: `${destDir}/${name}/README.md`
default: `${getGitHttpsUrl(await getRemoteGitUrl())}/timeline-${name}/README.md`, // '/timeline-${name}/README.md' if not a Git repository
});
} else {
readmePath = `https://github.com/jspsych/jspsych-timelines/packages/timeline-${name}/README.md`;
}

return {
isTimelinesRepo: isTimelinesRepo,
destDir: destDir,
name: name,
description: description,
author: author,
authorUrl: authorUrl,
language: language,
readmePath: readmePath
readmePath: readmePath,
destDir: cwdInfo.destDir,
isTimelinesRepo: cwdInfo.isTimelinesRepo,
};
}

async function processAnswers(answers) {
answers.name = formatName(answers.name);
const camelCaseName =
answers.name.charAt(0).toUpperCase() +
answers.name.slice(1).replace(/-([a-z])/g, (g) => g[1].toUpperCase());

const globalName = "jsPsychTimeline" + camelCaseName;
const packageFilename = `timeline-${answers.name}`;
const destPath = path.join(answers.destDir, packageFilename);
const readmePath = (() => {
answers.name = hyphenateName(answers.name);
const globalName = "jsPsychTimeline" + camelCaseName(answers.name);
const packageName = `timeline-${answers.name}`;
const destPath = path.join(answers.destDir, packageName);
const npmPackageName = (() => {
if (answers.isTimelinesRepo) {
return `https://github.com/jspsych/jspsych-timelines/packages/${answers.name}/README.md`
}
else {
return answers.readmePath;
return `@jspsych-timelines/${packageName}`;
} else {
return packageName;
}
})();

const templatesDir = path.resolve(__dirname, "../templates");
const gitRootUrl = await getRemoteGitRootUrl();
const gitRootHttpsUrl = getGitHttpsUrl(gitRootUrl);

function processTemplate() {
return src(`${templatesDir}/timeline-template-${answers.language}/**/*`)
.pipe(replace("{name}", answers.name))
.pipe(replace("{full name}", packageFilename))
.pipe(replace("{name}", `timeline-${answers.name}`))
.pipe(replace("{npmPackageName}", npmPackageName))
.pipe(replace("{description}", answers.description))
.pipe(replace("{author}", answers.author))
.pipe(replace("{authorUrl}", answers.authorUrl))
.pipe(replace("_globalName_", globalName))
.pipe(replace("{globalName}", globalName))
.pipe(replace("{camelCaseName}", camelCaseName))
.pipe(replace("ExtensionNameExtension", `${camelCaseName}Extension`))
.pipe(replace("{documentation-url}", readmePath))
.pipe(replace("{packageName}", packageName))
.pipe(replace("{gitRootUrl}", gitRootUrl))
.pipe(replace("{gitRootHttpsUrl}", gitRootHttpsUrl))
.pipe(replace("{documentationUrl}", answers.readmePath))
.pipe(dest(destPath));
}

Expand All @@ -163,17 +217,27 @@ async function processAnswers(answers) {

function renameReadmeTemplate() {
return src(`${destPath}/README.md`)
.pipe(
replace(
`{authorInfo}`,
answers.authorUrl ? `[${answers.author}](${answers.authorUrl})` : `${answers.author}`
)
.pipe(replace(`{npmPackageName}`, npmPackageName))
.pipe(
replace(
`{authorInfo}`,
answers.authorUrl ? `[${answers.author}](${answers.authorUrl})` : `${answers.author}`
)
.pipe(dest(destPath));
}
)
.pipe(
replace(
`## Loading`,
answers.isTimelinesRepo
? '## Loading\n\n### In browser\n\n```html\n<script src="https://unpkg.com/@jspsych-timelines/{name}">\n```\n\n### Via NPM\n\n```\nnpm install @jspsych-timelines/{name}\n```'
: `## Loading`
)
)
.pipe(dest(destPath));
}

series(processTemplate, renameExampleTemplate, renameDocsTemplate, renameReadmeTemplate)();
}

const answers = await runPrompts();
const cwdInfo = await getCwdInfo();
const answers = await runPrompts(cwdInfo);
await processAnswers(answers);
18 changes: 1 addition & 17 deletions packages/new-timeline/templates/timeline-template-ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,9 @@

## Loading

### In browser

```html
<script src="https://unpkg.com/@jspsych-timelines/{name}">
```
### Via NPM
```
npm install @jspsych-timelines/{name}
```
```js
import { createTimeline, timelineUnits, utils } from "@jspsych-timelines/{name}"
```
## Compatibility

`@jspsych-timelines/{name}` requires jsPsych v7.0.0 or later.
`{npmPackageName}` requires jsPsych v7.0.0 or later.

## Documentation

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@jspsych-timelines/{name}",
"name": "{npmPackageName}",
"version": "0.0.1",
"description": "{description}",
"type": "module",
Expand All @@ -11,7 +11,7 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/jspsych/jspsych-timelines.git"
"url": "{gitRootUrl}"
},
"keywords": [
"jsPsych"
Expand All @@ -22,9 +22,9 @@
},
"license": "MIT",
"bugs": {
"url": "https://github.com/jspsych/jspsych-timelines/issues"
"url": "{gitRootHttpsUrl}/issues"
},
"homepage": "https://github.com/jspsych/jspsych-timelines/packages/{name}#readme",
"homepage": "{documentationUrl}",
"peerDependencies": {
"jspsych": "^8.0.1"
},
Expand Down

0 comments on commit a67b375

Please sign in to comment.