Skip to content

Commit

Permalink
Feat/schematic options (#149)
Browse files Browse the repository at this point in the history
* feat(scully): pick commits for prompts

picked commits from #100

* feat(scully): add options for @scullyio/init:markdown

* fix(scully): fix x-prompt description

* fix(scully): use yyyy-mm-dd format

* feat(scully): provide options for @scullyio/init:post

* fix(scully): fix filename for post

* fix(scully): remove defaults from `route` and `sourceDir`

* docs(scully): update options

* refactor(scully): split into smaller chainable Rules

* test(scully): add tests for ng-add schematic

* test(scully): add more schematic tests

* feat(scully): add `metaDataFile` option and tests

* test(scully): add test for using `target` option

* fix(scully): add correct Schema infos for add-blog

* test(scully): fix test
  • Loading branch information
d-koppenhagen authored and jorgeucano committed Jan 9, 2020
1 parent 1708e5c commit 9a9d4ea
Show file tree
Hide file tree
Showing 24 changed files with 700 additions and 228 deletions.
20 changes: 19 additions & 1 deletion docs/blog.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ or
ng g @scullyio/init:markdown --name="my text" --slug="my slug id"
```

the following table shows all vailable options:

| option | description | default |
| -------------- | ------------------------------------------------------------------------------ | ------------------------ |
| `name` | define the name for the created module | 'blog' |
| `slug` | define the name for the `:slug` | 'id' |
| `routingScope` | set a routing scope (`Root` or `Child`) | Child |
| `sourceDir` | define a source dir name (when not used, `name` is used instead) | value from `name` option |
| `route` | define a route path before the `:slug` (when not used, `name` is used instead) | value from `name` option |

> If your markdown content will include code blocks, you may want the [code to be highlighted](utils.md).
## Generating New Blog Posts
Expand All @@ -41,7 +51,15 @@ To add a new blog post, run the following command.
ng g @scullyio/init:post --name="This is my post"
```

[Check how to integrate Scully with other tools.](utils.md)
the following table shows all vailable options:

| option | description | default |
| -------------- | ------------------------------------------------------ | --------- |
| `name` | define the name for the created post | 'blog-X' |
| `target` | define the target directory for the new post file | 'blog' |
| `metaDataFile` | use a meta data yaml template from a file for the post | undefined |

[Check how to integrate Scully with other tools.](utils.md)

---

Expand Down
8 changes: 8 additions & 0 deletions schematics/scully/assets/meta-data-template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
title: override-me
thumbnail: assets/images/default.jpg
author: John Doe
mail: John.Doe@example.com
keywords:
- angular
- scully
language: en
46 changes: 42 additions & 4 deletions schematics/scully/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions schematics/scully/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@
"@angular-devkit/core": "^9.0.0-rc.5",
"@angular-devkit/schematics": "^9.0.0-rc.5",
"@schematics/angular": "^9.0.0-rc.5",
"js-yaml": "^3.13.1",
"schematics-utilities": "^2.0.0"
},
"devDependencies": {
"@types/jasmine": "^3.3.9",
"@types/js-yaml": "^3.12.1",
"@types/node": "^8.0.31",
"jasmine": "^3.3.1",
"typescript": "~3.5.3"
Expand Down
18 changes: 13 additions & 5 deletions schematics/scully/src/add-blog/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
import {Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {RunSchematicTask} from '@angular-devkit/schematics/tasks';
import {Schema} from './schema';
import {Schema as MarkownSchema} from '../create-markdown/schema';

export default function(options: any): Rule {
export default function(options: Schema): Rule {
return (tree: Tree, context: SchematicContext) => {
options.name = 'blog';
options.slug = 'slug';
context.addTask(new RunSchematicTask('create-markdown', options), []);
const makrdownOptions: MarkownSchema = {
name: 'blog',
slug: 'slug',
};

if (options.routingScope) {
makrdownOptions.routingScope = options.routingScope;
}
context.addTask(new RunSchematicTask('create-markdown', makrdownOptions), []);
};
}
2 changes: 1 addition & 1 deletion schematics/scully/src/add-blog/schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/schema",
"id": "add-component",
"id": "add-blog",
"title": "Scully add component schematic",
"type": "object",
"properties": {
Expand Down
6 changes: 6 additions & 0 deletions schematics/scully/src/add-blog/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Schema {
/**
* The scope for the new routing module.
*/
routingScope?: 'Child' | 'Root';
}
57 changes: 42 additions & 15 deletions schematics/scully/src/add-post/index.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,54 @@
import { Rule, SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics';
import {Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics';
import {strings} from '@angular-devkit/core';
import fs = require('fs');
import yaml = require('js-yaml');

import {Schema} from './schema';
import { strings } from '@angular-devkit/core';

export default function(options: Schema): Rule {
return (host: Tree, context: SchematicContext) => {
const name = options.name;
const nameDasherized = options.name ? strings.dasherize(options.name) : 'blog-X';
const targetDasherized = options.target ? strings.dasherize(options.target) : 'blog';
const filename = `./${targetDasherized}/${nameDasherized}.md`;

let metaData = {
title: '',
description: 'blog description',
publish: false,
};

const name = options.name ? options.name : 'blog-X';
const namD = options.name ? strings.dasherize(options.name) : 'blog-X';
if (!host.exists(`./blog/${namD}.md`)) {
host.create(`./blog/${namD}.md`,
`---
title: ${name}
description: blog description
publish: false
---
if (options.metaDataFile) {
let metaDataContents = '';
try {
metaDataContents = fs.readFileSync(options.metaDataFile, 'utf8');
} catch (e) {
throw new SchematicsException(`File ${options.metaDataFile} not found`);
}

try {
// check if yaml is valid
metaData = yaml.safeLoad(metaDataContents);
context.logger.info(`✅️ Meta Data File ${options.metaDataFile} successfully parsed`);
} catch (e) {
throw new SchematicsException(`${options.metaDataFile} contains no valid yaml`);
}
}

// set title from option and override if alreay in metaDataFile template
metaData.title = name;

if (!host.exists(filename)) {
const content = `---
${yaml.safeDump(metaData)}---
# ${name}
`);
context.logger.info(`✅️Blog ${name} file created`);
`;
host.create(filename, content);
context.logger.info(`✅️ Blog ${filename} file created`);
} else {
// return name exist
throw new SchematicsException(`${name} exist in your blog folder`);
throw new SchematicsException(`${nameDasherized} exist in your ${targetDasherized} folder`);
}
};
}

75 changes: 75 additions & 0 deletions schematics/scully/src/add-post/index_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {HostTree} from '@angular-devkit/schematics';
import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing';
import {getFileContent} from '@schematics/angular/utility/test';
import * as path from 'path';

import {setupProject} from '../utils/test-utils';
import {Schema} from './schema';

const collectionPath = path.join(__dirname, '../collection.json');
const META_DATA_TEMPLATE_PATH = 'assets/meta-data-template.yml';

describe('add-post', () => {
const schematicRunner = new SchematicTestRunner('scully-schematics', collectionPath);
const project = 'foo';
const defaultOptions: Schema = {
name: 'Foo barBaz',
};
let appTree: UnitTestTree;
const expectedFileName = '/blog/foo-bar-baz.md';

beforeEach(async () => {
appTree = new UnitTestTree(new HostTree());
appTree = await setupProject(appTree, schematicRunner, project);
});

describe('when using the default options', () => {
beforeEach(async () => {
appTree = await schematicRunner.runSchematicAsync('post', defaultOptions, appTree).toPromise();
});

it('should create a new dasherized post', () => {
expect(appTree.files).toContain(expectedFileName);
const mdFileContent = getFileContent(appTree, expectedFileName);
expect(mdFileContent).toMatch(/title: Foo barBaz/g);
expect(mdFileContent).toMatch(/description: blog description/g);
expect(mdFileContent).toMatch(/publish: false/g);
});
});

describe('when using a different `target`', () => {
beforeEach(async () => {
appTree = await schematicRunner
.runSchematicAsync('post', {...defaultOptions, target: 'foo/bar'}, appTree)
.toPromise();
});

it('should create a new dasherized post inside the target dir', () => {
const expected = '/foo/bar/foo-bar-baz.md';
expect(appTree.files).toContain(expected);
const mdFileContent = getFileContent(appTree, expected);
expect(mdFileContent).toMatch(/title: Foo barBaz/g);
expect(mdFileContent).toMatch(/description: blog description/g);
expect(mdFileContent).toMatch(/publish: false/g);
});
});

describe('when using `metaDataFile` option', () => {
beforeEach(async () => {
appTree = await schematicRunner
.runSchematicAsync('post', {...defaultOptions, metaDataFile: META_DATA_TEMPLATE_PATH}, appTree)
.toPromise();
});

it('should add the meta data but keep title from options', () => {
expect(appTree.files).toContain(expectedFileName);
const mdFileContent = getFileContent(appTree, expectedFileName);
expect(mdFileContent).toMatch(/title: Foo barBaz/g);
expect(mdFileContent).toMatch(/thumbnail: assets\/images\/default\.jpg/g);
expect(mdFileContent).toMatch(/author: John Doe/g);
expect(mdFileContent).toMatch(/mail: John.Doe@example.com/g);
expect(mdFileContent).toMatch(/keywords:\s+-\ angular\s+-\ scully/s);
expect(mdFileContent).toMatch(/language: en/g);
});
});
});
16 changes: 14 additions & 2 deletions schematics/scully/src/add-post/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,20 @@
"name": {
"type": "string",
"description": "add the title for the post",
"x-prompt": "What title do you want to use for the post?"
"x-prompt": "What title do you want to use for the post?",
"default": "blog-X"
},
"target": {
"type": "string",
"description": "define the target directory for the new post file",
"x-prompt": "What's the target folder for this post?",
"default": "blog"
},
"metaDataFile": {
"type": "string",
"description": "use a meta data template file that's data will be added to the post",
"default": ""
}
},
"required": []
"required": ["name"]
}
16 changes: 15 additions & 1 deletion schematics/scully/src/add-post/schema.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
/**
* Scully ng-add-blog schematic
*/
export interface Schema {
name: string;
/**
* add the title for the post
*/
name: string;
/**
* define the target directory for the new post file
*/
target?: string;
/**
* use a meta data template file that's data will be added to the post
*/
metaDataFile?: string;
}
1 change: 1 addition & 0 deletions schematics/scully/src/collection.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"id": "scully-schematics",
"schematics": {
"ng-add": {
"description": "Add scully to the application.",
Expand Down
Loading

0 comments on commit 9a9d4ea

Please sign in to comment.