Add API for frameworks and examples (#3514)

* Add API for frameworks and examples

* Adjust headers

* Update frameworks list

* Always use latest

* Add types

* Use now repo for downloading and listing

* Use .existsSync

* Remove unused packages

* Use 307 for redirect

* Add examples

* Update tsconfig.json

Co-Authored-By: Steven <steven@ceriously.com>

* Make examples unique

* Remove detectors from frameworks API

* Use /api instead of Next.js

* Install dependencies

* Rename project

* Change name

* Empty

* Change name

* Update api/tsconfig.json

Co-Authored-By: Steven <steven@ceriously.com>

* Update examples

Co-authored-by: Steven <steven@ceriously.com>
This commit is contained in:
Andy
2020-01-07 23:55:39 +01:00
committed by GitHub
parent 537d508a1e
commit 890de6a625
912 changed files with 30138 additions and 0 deletions

View File

@@ -1,5 +1,6 @@
node_modules
dist
examples
# gatsby-plugin-now
packages/gatsby-plugin-now/test/fixtures

2
.gitignore vendored
View File

@@ -21,3 +21,5 @@ packages/now-cli/test/dev/fixtures/**/public
packages/now-cli/test/fixtures/integration
test/lib/deployment/failed-page.txt
.DS_Store
.next
public

16
.nowignore Normal file
View File

@@ -0,0 +1,16 @@
*
# general
!.yarnrc
!run.js
!yarn.lock
!package.json
# api
!api/
!api/**
# packages
!packages/
!packages/frameworks
!packages/frameworks/**

View File

@@ -0,0 +1,21 @@
// Currently we read & parse the README file from zeit/now-examples
// TODO: create a `manifest.json` for zeit/now-examples
import fetch from 'node-fetch';
/**
* Fetch and parse the `Frameworks and Libraries` table
* in the README file of zeit/now-examples
*/
export async function getExampleList() {
const response = await fetch(
`https://raw.githubusercontent.com/zeit/now-examples/master/manifest.json`
);
if (response.status !== 200) {
console.log('manifest.json missing in zeit/now-examples');
return null;
}
return response.json();
}

View File

@@ -0,0 +1,18 @@
/**
* Download zip and extract to target directory
*/
import got from 'got';
import unzip from 'unzip-stream';
export async function extract(sourceUrl: string, targetPath: string) {
return new Promise((resolve, reject) => {
got
.stream(sourceUrl)
.pipe(unzip.Extract({ path: targetPath }))
.on('close', resolve)
.on('error', err => {
reject(new Error('Failed extracting from github.'));
});
});
}

View File

@@ -0,0 +1,70 @@
import fetch from 'node-fetch';
import { Repo } from '../types';
import { getExampleList } from './example-list';
/**
* Fetch the meta info of a public github repo
* @param {object} repo parsed by the `parse-github-url` package
*/
export async function getGitHubRepoInfo(repo: Repo) {
const response = await fetch(`https://api.github.com/repos/${repo.repo}`, {
headers: {
Accept: 'application/vnd.github.machine-man-preview+json',
},
});
if (response.status !== 200) {
console.log(`Non-200 response code from GitHub: ${response.status}`);
console.log(await response.text());
return null;
}
const parsed = await response.json();
if (parsed.full_name !== repo.repo) {
console.log(`Invalid response from GitHub`);
console.log(`Received:`, parsed);
return null;
}
const data: { [key: string]: any } = {
id: parsed.full_name,
name: parsed.name,
url: parsed.html_url,
owner: parsed.owner.login,
description: parsed.description,
homepage: parsed.homepage,
size: parsed.size,
createdAt: parsed.created_at,
updatedAt: parsed.updated_at,
stars: parsed.stargazers_count,
branch: repo.branch,
};
const subdirPath = repo.repo + '/tree/' + repo.branch + '/';
if (repo.path.startsWith(subdirPath)) {
// subdir
data.subdir = repo.path.slice(subdirPath.length).split('/');
}
if (data.id === 'zeit/now-examples' && data.subdir) {
// from our examples, add `homepage` and `description` fields
const example = data.subdir[0];
const exampleList = await getExampleList();
for (const item of exampleList) {
if (item.path === `/${example}`) {
data.homepage = item.demo;
data.description = item.description;
data.exampleName = item.example;
data.icon = item.icon;
data.tagline = item.tagline;
data.framework = item.framework;
return data;
}
}
}
return data;
}

View File

@@ -0,0 +1,45 @@
import fetch from 'node-fetch';
interface Repo {
repo: string;
owner: {
username: string;
};
username: string;
branch: string;
}
/**
* Fetch the meta info of a public gitlab repo
* @param {object} repo parsed by the `parse-github-url` package
*/
export async function getGitLabRepoInfo(repo: Repo) {
const response = await fetch(
`https://gitlab.com/api/v4/projects/${encodeURIComponent(repo.repo)}`
);
if (response.status !== 200) {
console.log(`Non-200 response code from GitLab: ${response.status}`);
return null;
}
const parsed = await response.json();
if (parsed.path_with_namespace !== repo.repo) {
console.log(`Invalid response from GitLab`);
return null;
}
return {
id: parsed.path_with_namespace,
name: parsed.path,
url: parsed.web_url,
owner: parsed.owner ? parsed.owner.username : repo.owner,
description: parsed.description,
homepage: null,
size: 0,
createdAt: parsed.created_at,
updatedAt: parsed.last_activity_at,
stars: parsed.star_count,
branch: repo.branch,
};
}

View File

@@ -0,0 +1,27 @@
export const mapOldToNew: { [key: string]: string[] } = {
'go-image-to-ascii': ['vanilla-functions'],
markdown: ['hexo', 'docusaurus', 'docz', 'jekyll'],
'mdx-deck': ['docz'],
'mdx-deck-advanced': ['docz'],
'nextjs-mysql': ['nextjs'],
'nextjs-news': ['nextjs'],
'nextjs-nodejs-mongodb': ['nextjs'],
'nextjs-static': ['nextjs'],
'node-server': ['svelte-functions'],
nodejs: ['svelte-functions'],
'nodejs-canvas-partyparrot': ['svelte-functions'],
'nodejs-coffee': ['svelte-functions'],
'nodejs-hapi': ['svelte-functions'],
'nodejs-koa': ['svelte-functions'],
'nodejs-koa-ts': ['gatsby-functions'],
'nodejs-micro': ['svelte-functions'],
'nodejs-ms-graph-security-api': ['svelte-functions'],
'nodejs-pdfkit': ['svelte-functions'],
'nodejs-ts': ['gatsby-functions'],
'nuxt-static': ['nuxtjs'],
static: ['vanilla'],
typescript: ['gatsby-functions'],
'vanilla-go': ['vanilla-functions'],
'vanilla-json-api': ['svelte-functions'],
'vue-ssr': ['vue'],
};

View File

@@ -0,0 +1,20 @@
/**
* Get example list from extracted folder
*/
import { join } from 'path';
import { lstatSync, existsSync, readdirSync } from 'fs';
const exists = (path: string) => existsSync(path);
const isDotFile = (name: string) => name.startsWith('.');
const isDirectory = (path: string) => lstatSync(path).isDirectory();
export function summary(source: string) {
if (!exists(source) || !isDirectory(source)) {
return [];
}
return readdirSync(source)
.filter(name => !isDotFile(name))
.filter(name => isDirectory(join(source, name)));
}

9
api/_lib/types.ts Normal file
View File

@@ -0,0 +1,9 @@
export interface Repo {
repo: string;
owner: {
username: string;
};
username: string;
branch: string;
path: string;
}

View File

@@ -0,0 +1,29 @@
import { NowRequest, NowResponse } from '@now/node';
type Handler = (req: NowRequest, res: NowResponse) => Promise<any>;
export function withApiHandler(handler: Handler): Handler {
return async (req: NowRequest, res: NowResponse) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET');
res.setHeader(
'Access-Control-Allow-Headers',
'Authorization, Accept, Content-Type'
);
if (req.method === 'OPTIONS') {
return res.status(200).json({});
}
if (req.method !== 'GET') {
return res.status(404).json({
error: {
code: 'not_found',
message: 'Only GET requests are supported for this endpoint.',
},
});
}
return handler(req, res);
};
}

View File

@@ -0,0 +1,70 @@
import fs from 'fs';
// @ts-ignore
import tar from 'tar-fs';
import { extract } from '../../_lib/examples/extract';
import { NowRequest, NowResponse } from '@now/node';
import { withApiHandler } from '../../_lib/util/with-api-handler';
const TMP_DIR = '/tmp';
function isDirectory(path: string) {
return fs.existsSync(path) && fs.lstatSync(path).isDirectory();
}
function notFound(res: NowResponse, message: string) {
return res.status(404).send({
error: {
code: 'not_found',
message
}
});
}
function streamToBuffer(stream: any) {
return new Promise((resolve, reject) => {
const buffers: any[] = [];
stream.on('error', (err: any) => {
reject(err);
});
stream.on('data', (b: any) => {
buffers.push(b);
});
stream.on('end', () => {
resolve(Buffer.concat(buffers));
});
});
}
export default withApiHandler(async function(req: NowRequest, res: NowResponse) {
const ext = '.tar.gz';
const { segment = '' } = req.query;
if (Array.isArray(segment) || !segment.endsWith(ext)) {
return notFound(res, `Missing ${ext} suffix.`);
}
const example = segment.slice(0, -ext.length);
let directory;
if (Number(req.query.version) === 1) {
// The old cli is pinned to a specific commit hash
await extract('https://github.com/zeit/now-examples/archive/7c7b27e49b8b17d0d3f0e1604dc74fd005cd69e3.zip', TMP_DIR);
directory = `${TMP_DIR}/now-examples-7c7b27e49b8b17d0d3f0e1604dc74fd005cd69e3/${example}`;
} else {
await extract('https://github.com/zeit/now-examples/archive/master.zip', TMP_DIR);
directory = `${TMP_DIR}/now-examples-master/${example}`;
if (!isDirectory(directory)) {
// Use `now` instead of `now-examples` if the searched example does not exist
await extract('https://github.com/zeit/now/archive/master.zip', TMP_DIR);
directory = `${TMP_DIR}/now-master/examples/${example}`;
}
}
if (!isDirectory(directory)) {
return notFound(res, `Example '${example}' was not found.`);
}
const stream = tar.pack(directory);
return res.send(await streamToBuffer(stream));
});

44
api/examples/info.ts Normal file
View File

@@ -0,0 +1,44 @@
// A proxy to get the basic info of an existing github/gitlab repo:
// GET /info?repo=zeit/micro
// @ts-ignore
import parseGitUrl from 'parse-github-url';
import { NowRequest, NowResponse } from '@now/node';
import { withApiHandler } from '../_lib/util/with-api-handler';
import { getGitHubRepoInfo } from '../_lib/examples/github-repo-info';
import { getGitLabRepoInfo } from '../_lib/examples/gitlab-repo-info';
export default withApiHandler(async function(
req: NowRequest,
res: NowResponse
) {
const repoPath = decodeURIComponent((req.query.repo as string) || '');
if (!repoPath) {
return res.status(404).json({
error: {
code: 'not_found',
message: 'Please provide the `repo` parameter.',
},
});
}
const repo = parseGitUrl(repoPath);
if (!repo.repo) {
return res.status(400).json({
error: {
code: 'invalid_repo_url',
message: 'Repository URL is invalid.',
},
});
}
if (repo.host === 'github.com') {
// URL is 'https://github.com/user/repo' or 'user/repo'
return res.json((await getGitHubRepoInfo(repo)) || {});
}
// gitlab
res.json((await getGitLabRepoInfo(repo)) || {});
});

10
api/examples/list-all.ts Normal file
View File

@@ -0,0 +1,10 @@
import { NowRequest, NowResponse } from '@now/node';
import { getExampleList } from '../_lib/examples/example-list';
import { withApiHandler } from '../_lib/util/with-api-handler';
export default withApiHandler(async function(
req: NowRequest,
res: NowResponse
) {
res.status(200).json(await getExampleList());
});

46
api/examples/list.ts Normal file
View File

@@ -0,0 +1,46 @@
import { extract } from '../_lib/examples/extract';
import { summary } from '../_lib/examples/summary';
import { NowRequest, NowResponse } from '@now/node';
import { mapOldToNew } from '../_lib/examples/map-old-to-new';
import { withApiHandler } from '../_lib/util/with-api-handler';
export default withApiHandler(async function(
req: NowRequest,
res: NowResponse
) {
if (Number(req.query.version) === 1) {
// The old cli is pinned to a specific commit hash
await extract(
'https://github.com/zeit/now-examples/archive/7c7b27e49b8b17d0d3f0e1604dc74fd005cd69e3.zip',
'/tmp'
);
const exampleList = summary(
'/tmp/now-examples-7c7b27e49b8b17d0d3f0e1604dc74fd005cd69e3'
);
return res.send(exampleList);
}
await Promise.all([
extract('https://github.com/zeit/now/archive/master.zip', '/tmp'),
extract('https://github.com/zeit/now-examples/archive/master.zip', '/tmp'),
]);
const exampleList = new Set([
...summary('/tmp/now-master/examples'),
...summary('/tmp/now-examples-master'),
]);
const existingExamples = Array.from(exampleList).map(key => ({
name: key,
visible: true,
suggestions: [],
}));
const oldExamples = Object.keys(mapOldToNew).map(key => ({
name: key,
visible: false,
suggestions: mapOldToNew[key],
}));
res.status(200).json([...existingExamples, ...oldExamples]);
});

22
api/frameworks.ts Normal file
View File

@@ -0,0 +1,22 @@
import { NowRequest, NowResponse } from '@now/node';
import { withApiHandler } from './_lib/util/with-api-handler';
import frameworkList, { Framework } from '../packages/frameworks';
const frameworks: Framework[] = (frameworkList as Framework[]).map(
framework => {
delete framework.detectors;
if (framework.logo) {
framework.logo = `https://res.cloudinary.com/zeit-inc/image/fetch/${framework.logo}`;
}
return framework;
}
);
export default withApiHandler(async function(
req: NowRequest,
res: NowResponse
) {
return res.status(200).json(frameworks);
});

23
api/package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "api",
"private": true,
"version": "0.0.0",
"description": "API for the zeit/now repo",
"main": "index.js",
"scripts": {
"build": "yarn --cwd .. && node ../run.js build all"
},
"dependencies": {
"got": "10.2.1",
"node-fetch": "2.6.0",
"parse-github-url": "1.0.2",
"tar-fs": "2.0.0",
"typescript": "3.7.4",
"unzip-stream": "0.3.0"
},
"devDependencies": {
"@now/node": "1.3.3",
"@types/node": "13.1.4",
"@types/node-fetch": "2.5.4"
}
}

15
api/tsconfig.json Normal file
View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "esnext",
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "commonjs",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true
},
"include": ["examples", "frameworks.ts"]
}

349
api/yarn.lock Normal file
View File

@@ -0,0 +1,349 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@now/node@1.3.3":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@now/node/-/node-1.3.3.tgz#5407cb6a730d4dd9b6b6b0bc4a316f29086c9feb"
integrity sha512-s1qajtQttWhhSs1k6FX0/6eTFYFUplzultrQeKfOPMoYzzz6OxDq5qrQ3elpsGlZlDVmO+x+JOJ7yad+3yBgpg==
dependencies:
"@types/node" "*"
"@sindresorhus/is@^1.0.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-1.2.0.tgz#63ce3638cb85231f3704164c90a18ef816da3fb7"
integrity sha512-mwhXGkRV5dlvQc4EgPDxDxO6WuMBVymGFd1CA+2Y+z5dG9MNspoQ+AWjl/Ld1MnpCL8AKbosZlDVohqcIwuWsw==
"@szmarczak/http-timer@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.0.tgz#309789ccb7842ff1e41848cf43da587f78068836"
integrity sha512-3yoXv8OtGr/r3R5gaWWNQ3VUoQ5G3Gmo8DXX95V14ZVvE2b7Pj6Ide9uIDON8ym4D/ItyfL9ejohYUPqOyvRXw==
dependencies:
defer-to-connect "^1.1.1"
"@types/cacheable-request@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976"
integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==
dependencies:
"@types/http-cache-semantics" "*"
"@types/keyv" "*"
"@types/node" "*"
"@types/responselike" "*"
"@types/http-cache-semantics@*":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a"
integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==
"@types/keyv@*":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7"
integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==
dependencies:
"@types/node" "*"
"@types/node-fetch@2.5.4":
version "2.5.4"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.4.tgz#5245b6d8841fc3a6208b82291119bc11c4e0ce44"
integrity sha512-Oz6id++2qAOFuOlE1j0ouk1dzl3mmI1+qINPNBhi9nt/gVOz0G+13Ao6qjhdF0Ys+eOkhu6JnFmt38bR3H0POQ==
dependencies:
"@types/node" "*"
"@types/node@*", "@types/node@13.1.4":
version "13.1.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.4.tgz#4cfd90175a200ee9b02bd6b1cd19bc349741607e"
integrity sha512-Lue/mlp2egZJoHXZr4LndxDAd7i/7SQYhV0EjWfb/a4/OZ6tuVwMCVPiwkU5nsEipxEf7hmkSU7Em5VQ8P5NGA==
"@types/responselike@*":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
dependencies:
"@types/node" "*"
binary@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79"
integrity sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=
dependencies:
buffers "~0.1.1"
chainsaw "~0.1.0"
bl@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==
dependencies:
readable-stream "^3.0.1"
buffers@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb"
integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s=
cacheable-lookup@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-0.2.1.tgz#f474ae2c686667d7ea08c43409ad31b2b31b26c2"
integrity sha512-BQ8MRjxJASEq2q+w0SusPU3B054gS278K8sj58QCLMZIso5qG05+MdCdmXxuyVlfvI8h4bPsNOavVUauVCGxrg==
dependencies:
keyv "^3.1.0"
cacheable-request@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.0.tgz#12421aa084e943ec81eac8c93e56af90c624788a"
integrity sha512-UVG4gMn3WjnAeFBBx7RFoprgOANIAkMwN5Dta6ONmfSwrCxfm0Ip7g0mIBxIRJZX9aDsoID0Ry3dU5Pr0csKKA==
dependencies:
clone-response "^1.0.2"
get-stream "^5.1.0"
http-cache-semantics "^4.0.0"
keyv "^3.0.0"
lowercase-keys "^2.0.0"
normalize-url "^4.1.0"
responselike "^2.0.0"
chainsaw@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98"
integrity sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=
dependencies:
traverse ">=0.3.0 <0.4"
chownr@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142"
integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==
clone-response@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
dependencies:
mimic-response "^1.0.0"
decompress-response@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-5.0.0.tgz#7849396e80e3d1eba8cb2f75ef4930f76461cb0f"
integrity sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==
dependencies:
mimic-response "^2.0.0"
defer-to-connect@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.1.tgz#88ae694b93f67b81815a2c8c769aef6574ac8f2f"
integrity sha512-J7thop4u3mRTkYRQ+Vpfwy2G5Ehoy82I14+14W4YMDLKdWloI9gSzRbV30s/NckQGVJtPkWNcW4oMAUigTdqiQ==
duplexer3@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
fs-constants@^1.0.0:
version "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==
get-stream@^5.0.0, get-stream@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
dependencies:
pump "^3.0.0"
got@10.2.1:
version "10.2.1"
resolved "https://registry.yarnpkg.com/got/-/got-10.2.1.tgz#7087485482fb31aa6e6399fd493dd04639da117b"
integrity sha512-IQX//hGm5oLjUj743GJG30U2RzjS58ZlhQQjwQXjsyR50TTD+etVMHlMEbNxYJGWVFa0ASgDVhRkAvQPe6M9iQ==
dependencies:
"@sindresorhus/is" "^1.0.0"
"@szmarczak/http-timer" "^4.0.0"
"@types/cacheable-request" "^6.0.1"
cacheable-lookup "^0.2.1"
cacheable-request "^7.0.0"
decompress-response "^5.0.0"
duplexer3 "^0.1.4"
get-stream "^5.0.0"
lowercase-keys "^2.0.0"
mimic-response "^2.0.0"
p-cancelable "^2.0.0"
responselike "^2.0.0"
to-readable-stream "^2.0.0"
type-fest "^0.8.0"
http-cache-semantics@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5"
integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==
inherits@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
json-buffer@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
keyv@^3.0.0, keyv@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
dependencies:
json-buffer "3.0.0"
lowercase-keys@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
mimic-response@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.0.0.tgz#996a51c60adf12cb8a87d7fb8ef24c2f3d5ebb46"
integrity sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ==
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
mkdirp@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
dependencies:
minimist "0.0.8"
node-fetch@2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
normalize-url@^4.1.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
p-cancelable@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e"
integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==
parse-github-url@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/parse-github-url/-/parse-github-url-1.0.2.tgz#242d3b65cbcdda14bb50439e3242acf6971db395"
integrity sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
readable-stream@^3.0.1, readable-stream@^3.1.1:
version "3.4.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc"
integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
responselike@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
dependencies:
lowercase-keys "^2.0.0"
safe-buffer@~5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
dependencies:
safe-buffer "~5.2.0"
tar-fs@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad"
integrity sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==
dependencies:
chownr "^1.1.1"
mkdirp "^0.5.1"
pump "^3.0.0"
tar-stream "^2.0.0"
tar-stream@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3"
integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==
dependencies:
bl "^3.0.0"
end-of-stream "^1.4.1"
fs-constants "^1.0.0"
inherits "^2.0.3"
readable-stream "^3.1.1"
to-readable-stream@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-2.1.0.tgz#82880316121bea662cdc226adb30addb50cb06e8"
integrity sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==
"traverse@>=0.3.0 <0.4":
version "0.3.9"
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9"
integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=
type-fest@^0.8.0:
version "0.8.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
typescript@3.7.4:
version "3.7.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19"
integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==
unzip-stream@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/unzip-stream/-/unzip-stream-0.3.0.tgz#c30c054cd6b0d64b13a23cd3ece911eb0b2b52d8"
integrity sha512-NG1h/MdGIX3HzyqMjyj1laBCmlPYhcO4xEy7gEqqzGiSLw7XqDQCnY4nYSn5XSaH8mQ6TFkaujrO8d/PIZN85A==
dependencies:
binary "^0.3.0"
mkdirp "^0.5.1"
util-deprecate@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=

1
examples/amp/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.env

27
examples/amp/README.md Normal file
View File

@@ -0,0 +1,27 @@
# AMP Example
This directory is a brief example of an [AMP](https://amp.dev/) site that can be deployed with ZEIT Now and zero configuration.
## Deploy Your Own
Deploy your own AMP project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now-examples/tree/master/amp)
_Live Example: https://amp.now-examples.now.sh_
### How We Created This Example
To get started deploying AMP with ZEIT Now, you can use the [Now CLI](https://zeit.co/download) to initialize the project:
```shell
$ now init amp
```
### Deploying From Your Terminal
You can deploy your new AMP project with a single command from your terminal using Now CLI:
```shell
$ now
```

BIN
examples/amp/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

72
examples/amp/index.html Normal file
View File

@@ -0,0 +1,72 @@
<!DOCTYPE html>
<html >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,minimum-scale=1" />
<link rel="shortcut icon" href="favicon.png">
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
<link rel="canonical" href="index.html" />
<title>AMP Website</title>
<script async src="https://cdn.ampproject.org/v0.js"></script>
<style amp-custom>
body > * {
margin: 3rem 1rem;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
color: #525252;
}
h3 {
font-size: 2rem;
}
h4 {
margin-top: 2rem;
}
p {
font-size: 1.2rem;
line-height: 2rem;
}
.links {
display: flex;
justify-content: center;
margin-bottom: 3rem;
}
.links a {
margin: 0 10px;
font-size: 1rem;
color: #005af0;
}
</style>
</head>
<body>
<center>
<amp-img width=150 height=150 layout="fixed" class="logo" src="logo.png"></amp-img>
<h3>Welcome to your AMP page</h3>
<p>AMP is a web component framework to <br> easily create user-first websites, stories, ads and emails.</p>
<h4>Links</h4>
<div class="links">
<a href="https://amp.dev/">Homepage</a>
<a href="https://amp.dev/documentation/guides-and-tutorials/?format=websites">Tutorials</a>
<a href="https://amp.dev/documentation/examples/">Examples</a>
<a href="https://blog.amp.dev">Blog</a>
</div>
<h4>Ready to get started?</h4>
<div class="links">
<a href="https://amp.dev/documentation/guides-and-tutorials/start/create/?format=websites">Create your first AMP page</a>
</div>
<h4>Get involved</h4>
<div class="links">
<a href="https://twitter.com/amphtml">Twitter</a>
<a href="https://amphtml.slack.com">Slack</a>
<a href="https://amp.dev/events/amp-conf-2019">AMP Conf</a>
<a href="https://amp.dev/events/amp-roadshow">AMP Roadshow</a>
</div>
</center>
</body>
</html>

BIN
examples/amp/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1,13 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

50
examples/angular/.gitignore vendored Normal file
View File

@@ -0,0 +1,50 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out
# dependencies
/node_modules
# profiling files
chrome-profiler-events.json
speed-measure-plugin.json
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
# Environment Variables
.env
.env.build

View File

@@ -0,0 +1,2 @@
README.md
yarn.lock

View File

@@ -0,0 +1,29 @@
![Angular Logo](../.github/images/angular.svg)
# Angular Example
This directory is a brief example of an [Angular](https://angular.io/) app that can be deployed with ZEIT Now and zero configuration.
## Deploy Your Own
Deploy your own Angular project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now-examples/tree/master/angular)
_Live Example: https://angular.now-examples.now.sh_
### How We Created This Example
To get started with Angular, you can use the [Angular CLI](https://cli.angular.io/) to initialize the project:
```shell
$ ng new
```
### Deploying From Your Terminal
You can deploy your new Angular project with a single command from your terminal using [Now CLI](https://zeit.co/download):
```shell
$ now
```

View File

@@ -0,0 +1,109 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"angular": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/angular",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.css"],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "angular:build"
},
"configurations": {
"production": {
"browserTarget": "angular:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "angular:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.css"],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": ["**/node_modules/**"]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "angular:serve"
},
"configurations": {
"production": {
"devServerTarget": "angular:serve:production"
}
}
}
}
}
},
"defaultProject": "angular"
}

View File

@@ -0,0 +1,12 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

View File

@@ -0,0 +1,32 @@
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: ['./src/**/*.e2e-spec.ts'],
capabilities: {
browserName: 'chrome',
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {},
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json'),
});
jasmine
.getEnv()
.addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
},
};

View File

@@ -0,0 +1,28 @@
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('Welcome to angular!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser
.manage()
.logs()
.get(logging.Type.BROWSER);
expect(logs).not.toContain(
jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry)
);
});
});

View File

@@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}
getTitleText() {
return element(by.css('app-root h1')).getText() as Promise<string>;
}
}

View File

@@ -0,0 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types": ["jasmine", "jasminewd2", "node"]
}
}

View File

@@ -0,0 +1,32 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma'),
],
client: {
clearContext: false, // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/angular'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true,
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true,
});
};

View File

@@ -0,0 +1,48 @@
{
"name": "angular",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"dev": "ng serve --port $PORT",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "~8.1.0",
"@angular/common": "~8.1.0",
"@angular/compiler": "~8.1.0",
"@angular/core": "~8.1.0",
"@angular/forms": "~8.1.0",
"@angular/platform-browser": "~8.1.0",
"@angular/platform-browser-dynamic": "~8.1.0",
"@angular/router": "~8.1.0",
"rxjs": "~6.4.0",
"tslib": "^1.9.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.801.0",
"@angular/cli": "~8.1.0",
"@angular/compiler-cli": "~8.1.0",
"@angular/language-service": "~8.1.0",
"@types/node": "~8.9.4",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "~3.4.3"
}
}

View File

@@ -0,0 +1,20 @@
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/cli">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
</ul>

View File

@@ -0,0 +1,31 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'angular'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('angular');
});
it('should render title in a h1 tag', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain(
'Welcome to angular!'
);
});
});

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'angular';
}

View File

@@ -0,0 +1,12 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

View File

View File

@@ -0,0 +1,3 @@
export const environment = {
production: true,
};

View File

@@ -0,0 +1,16 @@
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false,
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Angular</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>

View File

@@ -0,0 +1,13 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));

View File

@@ -0,0 +1,62 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags.ts';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/

View File

@@ -0,0 +1 @@
/* You can add global styles to this file, and also import other style files */

View File

@@ -0,0 +1,20 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"include": ["src/**/*.ts"],
"exclude": ["src/test.ts", "src/**/*.spec.ts"]
}

View File

@@ -0,0 +1,21 @@
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"typeRoots": ["node_modules/@types"],
"lib": ["es2018", "dom"]
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}

View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": ["jasmine", "node"]
},
"files": ["src/test.ts", "src/polyfills.ts"],
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}

View File

@@ -0,0 +1,58 @@
{
"extends": "tslint:recommended",
"rules": {
"array-type": false,
"arrow-parens": false,
"deprecation": {
"severity": "warning"
},
"component-class-suffix": true,
"contextual-lifecycle": true,
"directive-class-suffix": true,
"directive-selector": [true, "attribute", "app", "camelCase"],
"component-selector": [true, "element", "app", "kebab-case"],
"import-blacklist": [true, "rxjs/Rx"],
"interface-name": false,
"max-classes-per-file": false,
"max-line-length": [true, 140],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-consecutive-blank-lines": false,
"no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
"no-empty": false,
"no-inferrable-types": [true, "ignore-params"],
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-switch-case-fall-through": true,
"no-use-before-declare": true,
"no-var-requires": false,
"object-literal-key-quotes": [true, "as-needed"],
"object-literal-sort-keys": false,
"ordered-imports": false,
"quotemark": [true, "single"],
"trailing-comma": false,
"no-conflicting-lifecycle": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-banana-in-box": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true
},
"rulesDirectory": ["codelyzer"]
}

14
examples/assemble/.gitattributes vendored Normal file
View File

@@ -0,0 +1,14 @@
# Enforce Unix newlines
*.* text eol=lf
*.css text eol=lf
*.html text eol=lf
*.js text eol=lf
*.json text eol=lf
*.less text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.jpg binary
*.gif binary
*.png binary
*.jpeg binary

47
examples/assemble/.gitignore vendored Normal file
View File

@@ -0,0 +1,47 @@
# Numerous always-ignore extensions
.ruby-version
*.diff
*.err
*.orig
*.log
*.rej
*.swo
*.swp
*.zip
*.vi
*~
# OS or Editor folders
*.esproj
*.sublime-project
*.sublime-workspace
._*
.cache
.DS_Store
.idea
.project
.settings
.tmproj
nbproject
Thumbs.db
# Komodo
*.komodoproject
.komodotools
# grunt-html-validation
validation-status.json
validation-report.json
# Folders to ignore
tmp
temp
TODO.md
vendor
node_modules
bower_components
_gh_pages
_site
_draft
.env
.env.build

View File

@@ -0,0 +1 @@
README.md

View File

@@ -0,0 +1,30 @@
/*
* assemble-examples <https://github.com/assemble/assemble-examples>
*
* Copyright (c) 2014 Jon Schlinkert, Brian Woodward, contributors.
* Licensed under the MIT license.
*/
module.exports = function(grunt) {
'use strict';
grunt.initConfig({
assemble: {
options: {
flatten: true,
partials: ['templates/includes/*.hbs'],
layoutdir: 'templates/layouts',
layout: 'default.hbs',
},
site: {
files: { 'public/index.js': ['templates/*.hbs'] },
},
},
});
// Load the Assemble plugin.
grunt.loadNpmTasks('assemble');
// The default task to run with the `grunt` command.
grunt.registerTask('default', ['assemble']);
};

View File

@@ -0,0 +1,27 @@
# Assemble Example
This directory is a brief example of a [Assemble](http://assemble.io/) app that can be deployed with ZEIT Now and zero configuration.
## Deploy Your Own
Deploy your own Assemble project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now-examples/tree/master/assemble)
_Live Example: https://assemble.now-examples.now.sh_
### How We Created This Example
To get started with Assemble deployed with ZEIT Now, you can use [Now CLI](https://zeit.co/download) to initialize the project:
```shell
$ now init assemble
```
### Deploying From Your Terminal
You can deploy your new Assemble project with a single command from your terminal using [Now CLI](https://zeit.co/download):
```shell
$ now
```

View File

@@ -0,0 +1,7 @@
# Blog post
> This is an example blog post
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

View File

@@ -0,0 +1,38 @@
{
"name": "assemble-example",
"private": true,
"description": "Example Assemble project.",
"version": "0.1.1",
"homepage": "https://github.com/jonschlinkert/assemble-example",
"scripts": {
"build": "grunt assemble"
},
"author": {
"name": "Jon Schlinkert",
"url": "https://github.com/jonschlinkert"
},
"repository": {
"type": "git",
"url": "https://github.com/jonschlinkert/assemble-example.git"
},
"bugs": {
"url": "https://github.com/jonschlinkert/assemble-example/issues"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/jonschlinkert/assemble-example/blob/master/LICENSE-MIT"
}
],
"main": "index.js",
"engines": {
"node": ">= 0.8.0"
},
"dependencies": {},
"devDependencies": {
"assemble": "~0.4.37",
"grunt": "~0.4.3",
"grunt-cli": "^1.3.2"
},
"keywords": []
}

View File

@@ -0,0 +1,7 @@
---
title: About
description: This is the about page.
---
<h2>{{description}}</h2>
{{> button }}

View File

@@ -0,0 +1,5 @@
---
title: Blog
---
{{md 'content/blog-post.md'}}

View File

@@ -0,0 +1,7 @@
---
title: Home
description: This is the home page.
---
<h2>{{description}}</h2>
{{> button }}

View File

@@ -0,0 +1 @@
<a href="https://github.com/assemble/assemble" class="btn btn-default">Star Assemble on GitHub!</a>

View File

@@ -0,0 +1,4 @@
<meta charset="UTF-8">
<title>{{title}}</title>
<link rel="stylesheet" href="http://getbootstrap.com/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="http://getbootstrap.com/assets/css/docs.min.css">

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
{{> head }}
</head>
<body>
<div class="container">
{{> body }}
</div>
</body>
</html>

View File

@@ -0,0 +1,35 @@
module.exports = api => {
api.cache.using(() => {
// cache based on the two env vars
return (
'babel:' +
process.env.BABEL_TARGET +
' protractor:' +
process.env.IN_PROTRACTOR
);
});
return {
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { loose: true }],
],
presets: [
[
'@babel/preset-env',
{
targets:
process.env.BABEL_TARGET === 'node'
? {
node: process.env.IN_PROTRACTOR ? '6' : 'current',
}
: {
browsers: ['last 2 versions'],
},
loose: true,
modules: process.env.BABEL_TARGET === 'node' ? 'commonjs' : false,
},
],
],
};
};

View File

@@ -0,0 +1,12 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# 2 space indentation
indent_style = space
indent_size = 2

41
examples/aurelia/.gitignore vendored Normal file
View File

@@ -0,0 +1,41 @@
# You may want to customise this file depending on your Operating System
# and the editor that you use.
#
# We recommend that you use a Global Gitignore for files that are not related
# to the project. (https://help.github.com/articles/ignoring-files/#create-a-global-gitignore)
# OS
#
# Ref: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
# Ref: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
# Ref: https://github.com/github/gitignore/blob/master/Global/Linux.gitignore
.DS_STORE
Thumbs.db
# Editors
#
# Ref: https://github.com/github/gitignore/blob/master/Global
# Ref: https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore
# Ref: https://github.com/github/gitignore/blob/master/Global/VisualStudioCode.gitignore
.idea
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# Dependencies
node_modules
# Compiled files
/scripts
/src/environment.js
/src/environment.ts
/dist
/test/coverage-jest
/test/coverage-karma
# Environment Variables
.env
.env.build

View File

@@ -0,0 +1,2 @@
README.md
yarn.lock

View File

@@ -0,0 +1,27 @@
# Aurelia Example
This directory is a brief example of an [Aurelia](https://aurelia.io/) app that can be deployed with ZEIT Now and zero configuration.
## Deploy Your Own
Deploy your own Aurelia project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now-examples/tree/master/aurelia)
_Live Example: https://aurelia.now-examples.now.sh_
### How We Created This Example
To get started deploying Aurelia with ZEIT Now, you can use the [Aurelia CLI](https://aurelia.io/docs/cli/basics/) to initialize the project:
```shell
$ au new
```
### Deploying From Your Terminal
You can deploy your new Aurelia project with a single command from your terminal using [Now CLI](https://zeit.co/download):
```shell
$ now
```

View File

@@ -0,0 +1,30 @@
{
"name": "aurelia",
"type": "project:application",
"paths": {
"root": "src",
"resources": "resources",
"elements": "resources/elements",
"attributes": "resources/attributes",
"valueConverters": "resources/value-converters",
"bindingBehaviors": "resources/binding-behaviors"
},
"transpiler": {
"id": "babel",
"fileExtension": ".js"
},
"build": {
"options": {
"server": "dev",
"extractCss": "prod",
"coverage": false
}
},
"platform": {
"hmr": false,
"open": false,
"port": 8080,
"output": "public"
},
"packageManager": "yarn"
}

View File

@@ -0,0 +1,4 @@
export default {
debug: true,
testing: true,
};

View File

@@ -0,0 +1,4 @@
export default {
debug: false,
testing: false,
};

View File

@@ -0,0 +1,4 @@
export default {
debug: true,
testing: false,
};

View File

@@ -0,0 +1,44 @@
import { inject } from 'aurelia-dependency-injection';
import { Project, ProjectItem, CLIOptions, UI } from 'aurelia-cli';
@inject(Project, CLIOptions, UI)
export default class AttributeGenerator {
constructor(project, options, ui) {
this.project = project;
this.options = options;
this.ui = ui;
}
async execute() {
const name = await this.ui.ensureAnswer(
this.options.args[0],
'What would you like to call the custom attribute?'
);
let fileName = this.project.makeFileName(name);
let className = this.project.makeClassName(name);
this.project.attributes.add(
ProjectItem.text(`${fileName}.js`, this.generateSource(className))
);
await this.project.commitChanges();
await this.ui.log(`Created ${fileName}.`);
}
generateSource(className) {
return `import {inject} from 'aurelia-framework';
@inject(Element)
export class ${className}CustomAttribute {
constructor(element) {
this.element = element;
}
valueChanged(newValue, oldValue) {
//
}
}
`;
}
}

View File

@@ -0,0 +1,4 @@
{
"name": "attribute",
"description": "Creates a custom attribute class and places it in the project resources."
}

View File

@@ -0,0 +1,41 @@
import { inject } from 'aurelia-dependency-injection';
import { Project, ProjectItem, CLIOptions, UI } from 'aurelia-cli';
@inject(Project, CLIOptions, UI)
export default class BindingBehaviorGenerator {
constructor(project, options, ui) {
this.project = project;
this.options = options;
this.ui = ui;
}
async execute() {
const name = await this.ui.ensureAnswer(
this.options.args[0],
'What would you like to call the binding behavior?'
);
let fileName = this.project.makeFileName(name);
let className = this.project.makeClassName(name);
this.project.bindingBehaviors.add(
ProjectItem.text(`${fileName}.js`, this.generateSource(className))
);
await this.project.commitChanges();
await this.ui.log(`Created ${fileName}.`);
}
generateSource(className) {
return `export class ${className}BindingBehavior {
bind(binding, source) {
//
}
unbind(binding, source) {
//
}
}
`;
}
}

View File

@@ -0,0 +1,4 @@
{
"name": "binding-behavior",
"description": "Creates a binding behavior class and places it in the project resources."
}

View File

@@ -0,0 +1,64 @@
import { inject } from 'aurelia-dependency-injection';
import { Project, ProjectItem, CLIOptions, UI } from 'aurelia-cli';
var path = require('path');
@inject(Project, CLIOptions, UI)
export default class ElementGenerator {
constructor(project, options, ui) {
this.project = project;
this.options = options;
this.ui = ui;
}
async execute() {
const name = await this.ui.ensureAnswer(
this.options.args[0],
'What would you like to call the component?'
);
const subFolders = await this.ui.ensureAnswer(
this.options.args[1],
"What sub-folder would you like to add it to?\nIf it doesn't exist it will be created for you.\n\nDefault folder is the source folder (src).",
'.'
);
let fileName = this.project.makeFileName(name);
let className = this.project.makeClassName(name);
this.project.root.add(
ProjectItem.text(
path.join(subFolders, fileName + '.js'),
this.generateJSSource(className)
),
ProjectItem.text(
path.join(subFolders, fileName + '.html'),
this.generateHTMLSource(className)
)
);
await this.project.commitChanges();
await this.ui.log(
`Created ${name} in the '${path.join(
this.project.root.name,
subFolders
)}' folder`
);
}
generateJSSource(className) {
return `export class ${className} {
constructor() {
this.message = 'Hello world';
}
}
`;
}
generateHTMLSource(className) {
return `<template>
<h1>\${message}</h1>
</template>
`;
}
}

View File

@@ -0,0 +1,4 @@
{
"name": "component",
"description": "Creates a custom component class and template (view model and view), placing them in the project source folder (or optionally in sub folders)."
}

View File

@@ -0,0 +1,49 @@
import { inject } from 'aurelia-dependency-injection';
import { Project, ProjectItem, CLIOptions, UI } from 'aurelia-cli';
@inject(Project, CLIOptions, UI)
export default class ElementGenerator {
constructor(project, options, ui) {
this.project = project;
this.options = options;
this.ui = ui;
}
async execute() {
const name = await this.ui.ensureAnswer(
this.options.args[0],
'What would you like to call the custom element?'
);
let fileName = this.project.makeFileName(name);
let className = this.project.makeClassName(name);
this.project.elements.add(
ProjectItem.text(`${fileName}.js`, this.generateJSSource(className)),
ProjectItem.text(`${fileName}.html`, this.generateHTMLSource(className))
);
await this.project.commitChanges();
await this.ui.log(`Created ${fileName}.`);
}
generateJSSource(className) {
return `import {bindable} from 'aurelia-framework';
export class ${className} {
@bindable value;
valueChanged(newValue, oldValue) {
//
}
}
`;
}
generateHTMLSource(className) {
return `<template>
<h1>\${value}</h1>
</template>
`;
}
}

View File

@@ -0,0 +1,4 @@
{
"name": "element",
"description": "Creates a custom element class and template, placing them in the project resources."
}

View File

@@ -0,0 +1,72 @@
import { inject } from 'aurelia-dependency-injection';
import { Project, ProjectItem, CLIOptions, UI } from 'aurelia-cli';
@inject(Project, CLIOptions, UI)
export default class GeneratorGenerator {
constructor(project, options, ui) {
this.project = project;
this.options = options;
this.ui = ui;
}
async execute() {
const name = await this.ui.ensureAnswer(
this.options.args[0],
'What would you like to call the generator?'
);
let fileName = this.project.makeFileName(name);
let className = this.project.makeClassName(name);
this.project.generators.add(
ProjectItem.text(`${fileName}.js`, this.generateSource(className))
);
await this.project.commitChanges();
await this.ui.log(`Created ${fileName}.`);
}
generateSource(className) {
return `import {inject} from 'aurelia-dependency-injection';
import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
@inject(Project, CLIOptions, UI)
export default class ${className}Generator {
constructor(project, options, ui) {
this.project = project;
this.options = options;
this.ui = ui;
}
execute() {
return this.ui
.ensureAnswer(this.options.args[0], 'What would you like to call the new item?')
.then(name => {
let fileName = this.project.makeFileName(name);
let className = this.project.makeClassName(name);
this.project.elements.add(
ProjectItem.text(\`\${fileName}.js\`, this.generateSource(className))
);
return this.project.commitChanges()
.then(() => this.ui.log(\`Created \${fileName}.\`));
});
}
generateSource(className) {
return \`import {bindable} from 'aurelia-framework';
export class \${className} {
@bindable value;
valueChanged(newValue, oldValue) {
//
}
}
\`
}
}
`;
}
}

View File

@@ -0,0 +1,4 @@
{
"name": "generator",
"description": "Creates a generator class and places it in the project generators folder."
}

View File

@@ -0,0 +1,39 @@
import { inject } from 'aurelia-dependency-injection';
import { Project, ProjectItem, CLIOptions, UI } from 'aurelia-cli';
@inject(Project, CLIOptions, UI)
export default class TaskGenerator {
constructor(project, options, ui) {
this.project = project;
this.options = options;
this.ui = ui;
}
async execute() {
const name = await this.ui.ensureAnswer(
this.options.args[0],
'What would you like to call the task?'
);
let fileName = this.project.makeFileName(name);
let functionName = this.project.makeFunctionName(name);
this.project.tasks.add(
ProjectItem.text(`${fileName}.js`, this.generateSource(functionName))
);
await this.project.commitChanges();
await this.ui.log(`Created ${fileName}.`);
}
generateSource(functionName) {
return `import gulp from 'gulp';
import project from '../aurelia.json';
export default function ${functionName}() {
return gulp.src(project.paths.???)
.pipe(gulp.dest(project.paths.output));
}
`;
}
}

View File

@@ -0,0 +1,4 @@
{
"name": "task",
"description": "Creates a task and places it in the project tasks folder."
}

View File

@@ -0,0 +1,41 @@
import { inject } from 'aurelia-dependency-injection';
import { Project, ProjectItem, CLIOptions, UI } from 'aurelia-cli';
@inject(Project, CLIOptions, UI)
export default class ValueConverterGenerator {
constructor(project, options, ui) {
this.project = project;
this.options = options;
this.ui = ui;
}
async execute() {
const name = await this.ui.ensureAnswer(
this.options.args[0],
'What would you like to call the value converter?'
);
let fileName = this.project.makeFileName(name);
let className = this.project.makeClassName(name);
this.project.valueConverters.add(
ProjectItem.text(`${fileName}.js`, this.generateSource(className))
);
await this.project.commitChanges();
await this.ui.log(`Created ${fileName}.`);
}
generateSource(className) {
return `export class ${className}ValueConverter {
toView(value) {
//
}
fromView(value) {
//
}
}
`;
}
}

View File

@@ -0,0 +1,4 @@
{
"name": "value-converter",
"description": "Creates a value converter class and places it in the project resources."
}

View File

@@ -0,0 +1,56 @@
import webpackConfig from '../../webpack.config';
import webpack from 'webpack';
import project from '../aurelia.json';
import gulp from 'gulp';
import del from 'del';
import { CLIOptions, Configuration } from 'aurelia-cli';
import configureEnvironment from './environment';
const analyze = CLIOptions.hasFlag('analyze');
const buildOptions = new Configuration(project.build.options);
const production = CLIOptions.getEnvironment() === 'prod';
const server = buildOptions.isApplicable('server');
const extractCss = buildOptions.isApplicable('extractCss');
const coverage = buildOptions.isApplicable('coverage');
const config = webpackConfig({
production,
server,
extractCss,
coverage,
analyze,
});
const compiler = webpack(config);
function buildWebpack(done) {
if (CLIOptions.hasFlag('watch')) {
compiler.watch({}, onBuild);
} else {
compiler.run(onBuild);
compiler.hooks.done.tap('done', () => done());
}
}
function onBuild(err, stats) {
if (!CLIOptions.hasFlag('watch') && err) {
console.error(err.stack || err);
if (err.details) console.error(err.details);
process.exit(1);
} else {
process.stdout.write(
stats.toString({ colors: require('supports-color') }) + '\n'
);
if (!CLIOptions.hasFlag('watch') && stats.hasErrors()) {
process.exit(1);
}
}
}
function clearDist() {
return del([config.output.path]);
}
const build = gulp.series(clearDist, configureEnvironment, buildWebpack);
export { config, buildWebpack, build as default };

View File

@@ -0,0 +1,21 @@
{
"name": "build",
"description": "Builds and processes all application assets.",
"flags": [
{
"name": "analyze",
"description": "Enable Webpack Bundle Analyzer. Typically paired with --env prod",
"type": "boolean"
},
{
"name": "env",
"description": "Sets the build environment.",
"type": "string"
},
{
"name": "watch",
"description": "Watches source files for changes and refreshes the bundles automatically.",
"type": "boolean"
}
]
}

View File

@@ -0,0 +1,38 @@
import project from '../aurelia.json';
import rename from 'gulp-rename';
import gulp from 'gulp';
import fs from 'fs';
import through from 'through2';
import { CLIOptions } from 'aurelia-cli';
function configureEnvironment() {
let env = CLIOptions.getEnvironment();
return gulp
.src(
`aurelia_project/environments/${env}${project.transpiler.fileExtension}`
)
.pipe(rename(`environment${project.transpiler.fileExtension}`))
.pipe(
through.obj(function(file, _, cb) {
// https://github.com/aurelia/cli/issues/1031
fs.unlink(`${project.paths.root}/${file.relative}`, function() {
cb(null, file);
});
})
)
.pipe(gulp.dest(project.paths.root))
.pipe(
through.obj(function(file, enc, cb) {
// https://github.com/webpack/watchpack/issues/25#issuecomment-287789288
const now = Date.now() / 1000;
const then = now - 10;
fs.utimes(file.path, then, then, function(err) {
if (err) throw err;
});
cb(null, file);
})
);
}
export default configureEnvironment;

View File

@@ -0,0 +1 @@
export { default } from './test';

View File

@@ -0,0 +1,11 @@
{
"name": "jest",
"description": "Runs Jest and reports the results.",
"flags": [
{
"name": "watch",
"description": "Watches test files for changes and re-runs the tests automatically.",
"type": "boolean"
}
]
}

View File

@@ -0,0 +1,54 @@
import webpack from 'webpack';
import Server from 'webpack-dev-server';
import project from '../aurelia.json';
import gulp from 'gulp';
import { config } from './build';
import configureEnvironment from './environment';
import { CLIOptions, reportWebpackReadiness } from 'aurelia-cli';
function runWebpack(done) {
// https://webpack.github.io/docs/webpack-dev-server.html
let opts = {
host: 'localhost',
publicPath: config.output.publicPath,
filename: config.output.filename,
hot: project.platform.hmr || CLIOptions.hasFlag('hmr'),
port: CLIOptions.getFlagValue('port') || project.platform.port,
contentBase: config.output.path,
historyApiFallback: true,
open: project.platform.open || CLIOptions.hasFlag('open'),
stats: {
colors: require('supports-color'),
},
...config.devServer,
};
// Add the webpack-dev-server client to the webpack entry point
// The path for the client to use such as `webpack-dev-server/client?http://${opts.host}:${opts.port}/` is not required
// The path used is derived from window.location in the browser and output.publicPath in the webpack.config.
if (project.platform.hmr || CLIOptions.hasFlag('hmr')) {
config.plugins.push(new webpack.HotModuleReplacementPlugin());
config.entry.app.unshift(
'webpack-dev-server/client',
'webpack/hot/dev-server'
);
} else {
// removed "<script src="/webpack-dev-server.js"></script>" from index.ejs in favour of this method
config.entry.app.unshift('webpack-dev-server/client');
}
const compiler = webpack(config);
let server = new Server(compiler, opts);
server.listen(opts.port, opts.host, function(err) {
if (err) throw err;
reportWebpackReadiness(opts);
done();
});
}
const run = gulp.series(configureEnvironment, runWebpack);
export { run as default };

View File

@@ -0,0 +1,31 @@
{
"name": "run",
"description": "Builds the application and serves up the assets via a local web server, watching files for changes as you work.",
"flags": [
{
"name": "analyze",
"description": "Enable Webpack Bundle Analyzer. Typically paired with --env prod",
"type": "boolean"
},
{
"name": "env",
"description": "Sets the build environment.",
"type": "string"
},
{
"name": "hmr",
"description": "Enable Hot Module Reload",
"type": "boolean"
},
{
"name": "port",
"description": "Set port number of the dev server",
"type": "string"
},
{
"name": "open",
"description": "Open the default browser at the application location.",
"type": "boolean"
}
]
}

View File

@@ -0,0 +1,25 @@
import jest from 'jest-cli';
import path from 'path';
import packageJson from '../../package.json';
import { CLIOptions } from 'aurelia-cli';
export default cb => {
let options = packageJson.jest;
if (CLIOptions.hasFlag('watch')) {
Object.assign(options, { watchAll: true });
}
process.env.BABEL_TARGET = 'node';
jest
.runCLI(options, [path.resolve(__dirname, '../../')])
.then(({ results }) => {
if (results.numFailedTests || results.numFailedTestSuites) {
cb('Tests Failed');
} else {
cb();
}
});
};

View File

@@ -0,0 +1,11 @@
{
"name": "test",
"description": "Runs Jest and reports the results.",
"flags": [
{
"name": "watch",
"description": "Watches test files for changes and re-runs the tests automatically.",
"type": "boolean"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files have changed in this diff Show More