Skip to content

Commit

Permalink
feat: Add support for generating a d2l.dev app
Browse files Browse the repository at this point in the history
  • Loading branch information
jorge-ramirez-arredondo committed Jun 3, 2024
1 parent dfe93bc commit 1083378
Show file tree
Hide file tree
Showing 17 changed files with 487 additions and 5 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"create-brightspace-ui": "./dist/create.js"
},
"scripts": {
"build": "rm -rf dist && babel src --out-dir dist --copy-files --include-dotfiles",
"build": "rimraf dist && babel src --out-dir dist --copy-files --include-dotfiles",
"lint:eslint": "eslint . --ext .js,.html",
"test": "npm run lint:eslint"
},
Expand All @@ -30,6 +30,7 @@
"babel-eslint": "^10",
"babel-plugin-transform-dynamic-import": "^2",
"eslint": "^8",
"eslint-config-brightspace": "^1"
"eslint-config-brightspace": "^1",
"rimraf": "^5.0.7"
}
}
144 changes: 141 additions & 3 deletions src/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,75 @@ import { run as setupLocalization } from './generators/localization/index.js';
import { run as setupRelease } from './generators/release/index.js';
import { run as setupTestUnit } from './generators/test-unit/index.js';
import { run as setupTestVdiff } from './generators/test-vdiff/index.js';
import { run as setupD2ldev } from './generators/d2ldev/index.js';

Check failure on line 12 in src/create.js

View workflow job for this annotation

GitHub Actions / Test

Imports should be sorted alphabetically

const generatorTypes = {
component: 'component',
d2ldevSite: 'd2ldevSite',
bsiApp: 'bsiApp'
};

const projectTypes = {
component: 'component',
app: 'app'
};

const applicationTypes = {
bsi: 'bsi',
d2ldev: 'd2ldev'
};

function getClassName(hyphenatedName) {
const hyphenRemoved = hyphenatedName.replace(/-([a-z])/g, (g) => { return g[1].toUpperCase(); });
return hyphenRemoved.charAt(0).toUpperCase() + hyphenRemoved.slice(1);
}

async function getOptions() {
async function getGeneratorType() {
const { projectType } = await prompts([
{
type: 'select',
name: 'projectType',
message: 'What type of project is this?',
choices: [
{ title: 'Component', value: projectTypes.component },
{ title: 'Application', value: projectTypes.app }
]
}
], {
onCancel: () => {
process.exit();
},
});

if (projectType === projectTypes.component) return generatorTypes.component;

const { applicationType } = await prompts([
{
type: 'select',
name: 'applicationType',
message: 'What type of application is this?',
choices: [
{ title: 'BSI', value: applicationTypes.bsi },
{ title: 'd2l.dev', value: applicationTypes.d2ldev }
]
}
], {
onCancel: () => {
process.exit();
},
});

switch (applicationType) {
case applicationTypes.d2ldev:
return generatorTypes.d2ldevSite;
case applicationTypes.bsi:
return generatorTypes.bsiApp;
default:
break;
}
}

async function getComponentOptions() {
const questions = [
{
type: 'text',
Expand Down Expand Up @@ -67,9 +129,9 @@ async function getOptions() {
});
}

async function executeGenerator() {
async function executeComponentGenerator() {

const options = await getOptions();
const options = await getComponentOptions();

/**
* hyphenatedName = my-element
Expand All @@ -94,6 +156,82 @@ async function executeGenerator() {

}

async function executeD2ldevSiteGenerator() {
const questions = [
{
type: 'text',
name: 'hyphenatedName',
message: 'What would you like to name your app? Use hyphenation instead of camelcase.'
},
{
type: 'select',
name: 'githubOrg',
message: 'Which GitHub org will the repo be in?',
choices: [
{ title: 'Brightspace', value: 'Brightspace' },
{ title: 'BrightspaceUI', value: 'BrightspaceUI' }
]
},
{
type: 'text',
name: 'subdomain',
message: 'What is the d2l.dev subdomain you want to publish this app to?'
},
{
type: 'text',
name: 'description',
message: 'What is the app description?'
},
{
type: 'text',
name: 'codeowners',
message: 'What is/are the GitHub username(s) of the codeowner(s)? (e.g., @janesmith, @johnsmith)'
},
];
const options = await prompts(questions, {
onCancel: () => {
process.exit();
},
});

const hyphenatedName = options.hyphenatedName.toLowerCase();
const templateData = {
hyphenatedName,
className: getClassName(options.hyphenatedName),
tagName: `d2l-${hyphenatedName}`,
githubOrg: options.githubOrg,
repoName: hyphenatedName,
subdomain: options.subdomain,
description: options.description,
codeowners: options.codeowners
};

setupD2ldev(templateData);
}

async function executeBsiAppGenerator() {
console.log('Sorry, the BSI Application template is not yet available.');
console.log('In the meantime, please create a Component project type and modify it to work as a BSI App.');
}

async function executeGenerator() {
const generatorType = await getGeneratorType();

switch (generatorType) {
case generatorTypes.component:
await executeComponentGenerator();
break;
case generatorTypes.d2ldevSite:
await executeD2ldevSiteGenerator();
break;
case generatorTypes.bsiApp:
await executeBsiAppGenerator();
break;
default:
break;
}
}

(async() => {
try {
await executeGenerator();
Expand Down
30 changes: 30 additions & 0 deletions src/generators/d2ldev/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import path from 'path';
import { copyAndProcessDir, getDestinationPath, replaceTextPlugin, movePlugin } from '../../helper.js';

Check failure on line 2 in src/generators/d2ldev/index.js

View workflow job for this annotation

GitHub Actions / Test

Expected 'multiple' syntax before 'single' syntax

Check failure on line 2 in src/generators/d2ldev/index.js

View workflow job for this annotation

GitHub Actions / Test

Member 'movePlugin' of the import declaration should be sorted alphabetically

export function run(templateData) {
const templateRoot = path.join(__dirname, 'templates');
const destinationRoot = getDestinationPath(templateData.hyphenatedName);

const elementFile = `${templateData.hyphenatedName}.js`;
copyAndProcessDir(templateRoot, destinationRoot, [
movePlugin({
'_package.json': 'package.json',
'_gitignore': '.gitignore',
'_CODEOWNERS': 'CODEOWNERS',
'_README.md': 'README.md',
'src/components/_element.js': `src/components/${elementFile}`
}),
replaceTextPlugin({
'_package.json': templateData,
'_CODEOWNERS': templateData,
'_README.md': templateData,
'.github/workflows/publish.yml': templateData,
'src/index.html': templateData,
'src/index.js': {
...templateData,
elementFile
},
'src/components/_element.js': templateData,
})
]);
}
40 changes: 40 additions & 0 deletions src/generators/d2ldev/templates/.github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Publish
on:
push:
branches:
- main
- '[0-9]+.x'
- '[0-9]+.[0-9]+.x'
jobs:
publish:
name: Publish
runs-on: [self-hosted, AWS, Linux]
timeout-minutes: 10
steps:
- name: Checkout
uses: Brightspace/third-party-actions@actions/checkout
- name: Setup Node
uses: Brightspace/third-party-actions@actions/setup-node
with:
node-version-file: .nvmrc
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build

- name: Assume role
if: github.ref == 'refs/heads/main'
uses: Brightspace/third-party-actions@aws-actions/configure-aws-credentials
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
role-to-assume: "arn:aws:iam::022062736489:role/r+<%= githubOrg %>+<%= repoName %>+repo"
role-duration-seconds: 3600
aws-region: ca-central-1

- name: Publish
uses: BrightspaceUI/actions/publish-to-s3@main
with:
bucket-path: s3://d2l.dev/<%= subdomain %>/main
publish-directory: ./dist/
1 change: 1 addition & 0 deletions src/generators/d2ldev/templates/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20
1 change: 1 addition & 0 deletions src/generators/d2ldev/templates/_CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* <%= codeowners %>
12 changes: 12 additions & 0 deletions src/generators/d2ldev/templates/_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# <%= hyphenatedName %>

## Developing and Contributing

* Clone the repo
* Run `npx d2l-npm-login` to support private npm packages (note: this requires your Okta credentials)
* Run `npm install` to install dependencies
* Run `npm start` to run the local web-dev-server

## Releasing

After merging your code changes to the `main` branch, the `Publish` Github action will run and publish your changes to [<%= subdomain %>.d2l.dev](https://<%= subdomain %>.d2l.dev/).
3 changes: 3 additions & 0 deletions src/generators/d2ldev/templates/_gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
package-lock.json
dist/
28 changes: 28 additions & 0 deletions src/generators/d2ldev/templates/_package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "<%= hyphenatedName %>",
"description": "<%= description %>",
"type": "module",
"repository": "https://github.com/<%= githubOrg %>/<%= repoName %>.git",
"scripts": {
"start": "web-dev-server --watch",
"build": "rimraf dist && rollup -c rollup.config.js"
},
"keywords": [],
"author": "D2L Corporation",
"license": "Apache-2.0",
"dependencies": {
"@brightspace-ui/core": "^3",
"lit": "^3"
},
"devDependencies": {
"@rollup/plugin-dynamic-import-vars": "^2",
"@rollup/plugin-node-resolve": "^15",
"@rollup/plugin-replace": "^5",
"@rollup/plugin-terser": "^0",
"@web/dev-server": "^0",
"@web/dev-server-rollup": "^0",
"@web/rollup-plugin-html": "^2",
"rimraf": "^5",
"rollup": "^4"
}
}
40 changes: 40 additions & 0 deletions src/generators/d2ldev/templates/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';
import replace from '@rollup/plugin-replace';
import resolve from '@rollup/plugin-node-resolve';
import { rollupPluginHTML as html } from '@web/rollup-plugin-html';
import terser from '@rollup/plugin-terser';

import { prodConfig } from './shared.config.js';

export default {
input: './src/index.html',
output: {
dir: 'dist',
entryFileNames: '[hash].js',
chunkFileNames: '[hash].js',
assetFileNames: '[hash][extname]',
},
plugins: [
replace({
// The buildConfig replace is set up to only work in the buildConfig.js file in order to limit the use of undefined (i.e. magic-y) variables
include: ['./src/**/buildConfig.js'],
preventAssignment: true,
values: {
__buildConfig__: JSON.stringify(prodConfig),
},
}),
resolve(),
html({
minify: true,
input: './src/index.html',
}),

/*
dynamicImportVars is required in order to properly handle
dynamic imports for @brightspace-ui/core's localization.
*/
dynamicImportVars(),

terser(),
],
};
7 changes: 7 additions & 0 deletions src/generators/d2ldev/templates/shared.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const devConfig = {
development: true,
};

export const prodConfig = {
development: false,
};
36 changes: 36 additions & 0 deletions src/generators/d2ldev/templates/src/components/_element.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { css, html, LitElement } from 'lit';
import '@brightspace-ui/core/components/alert/alert.js';
import buildConfig from '../utilities/buildConfig.js';

class <%= className %> extends LitElement {

static get properties() {
return {
prop1: { type: String },
};
}

static get styles() {
return css`
:host([hidden]) {
display: none;
}
`;
}

constructor() {
super();

this.prop1 = '<%= hyphenatedName %>';
}

render() {
return html`
Hello ${this.prop1}!
<d2l-alert type="default">
Development: ${buildConfig.development ? 'True' : 'False'}
</d2l-alert>
`;
}
}
customElements.define('<%= tagName %>', <%= className %>);
Loading

0 comments on commit 1083378

Please sign in to comment.