SlideShare a Scribd company logo
ANGULARANGULAR
SCHEMATICSSCHEMATICS
THE UNKNOWN HEROTHE UNKNOWN HERO
CHRIS NORINGCHRIS NORING
CLOUD DEVELOPER EXPERT AT MICROSOFTCLOUD DEVELOPER EXPERT AT MICROSOFT
Google Developer Expert in Angular and Web Techs
@chris_noring
https://so chris.github.io
Published author
Public Speaker
So ware Engineer
WORKFLOW TOOLWORKFLOW TOOL
CAN APPLY TRANSFORMS TO YOUR PROJECTCAN APPLY TRANSFORMS TO YOUR PROJECT
example of usage:
scaffold: new components, services,
update your code to fix breaking changes in
dependencies.
or add a new configuration option or framework to
an existing project
ANGULAR CLI - SECRET SAUCEANGULAR CLI - SECRET SAUCE
GENERIC FACILITY TO SUPPORT THE CLIGENERIC FACILITY TO SUPPORT THE CLI
SCAFFOLDINGSCAFFOLDING
improve your development productivity
Ease uf use and development
Extensibility and reuseability
Atomicity
Asynchronicity
TREETREE
OVER FILE SYSTEMOVER FILE SYSTEM
not affecting the file system directly,
you describe what transformations you
want done on a Tree
INSTALLATIONINSTALLATION
npm install -g @angular-devkit/schematics-cli
This will install a schematics
executable, which you can use to
create a blank Schematics project
EXAMPLEEXAMPLE
YOUR FIRST SCHEMATICYOUR FIRST SCHEMATIC
schematics blank --name=my-component
Angular Schematics
index.ts, where our rules live
collection.json, a description of our project
INDEX.TSINDEX.TS
return a function of type Rule
options input, is an object representing command
line args
inner function takes Tree and SchematicContext,
tree is file tree
index.ts
COLLECTION.JSONCOLLECTION.JSON
description, description of project
factory, points to the directory/starter module
collection.json
BUILD AND RUNBUILD AND RUN
--name=test, command line arg
npm run build
schematics .:my-component --name=test
it says: nothing to be done!!
not surprised, cause our Rule factory function does
nothing
EXAMPLEEXAMPLE
SCAFFOLD SOME FILES, WITH CONTENTSCAFFOLD SOME FILES, WITH CONTENT
update Rule factory function
create files, with content
tree.create(filename, file-content)
let's create a build and run script
npm run execute
Angular Schematics
we didn't actual create any files, we are in dry-run
mode
It shows what would happen if applied
to a file system
let's shut off dry-run
I don't see a difference??
oh, so they were created in the in the project
Just add the follwing to your schematics executable
--dry-run=false
There are four methods that directly create a change in
a Tree
create
delete
rename
overwrite
TIPS AND TRICKSTIPS AND TRICKS
watch mode, rebuild your project on changes
npm run build -w
Debugging
node --inspect-brk <path_to_schematics>/schematics
.:myComponent --name=test
TESTING OUT YOUR SCHEMATICSTESTING OUT YOUR SCHEMATICS
scaffold an Angular project
npm link to the schematics
ng generate
ng new SchematicsDemo
npm link <path to schematics>
// tip: run pwd and copy result
ng generate my-service:my-service someName
Angular Schematics
Voila, our Vikings are added
EXAMPLEEXAMPLE
USING AN EXISTING SCHEMATICUSING AN EXISTING SCHEMATIC
WHAT IS A COLLECTION?WHAT IS A COLLECTION?
Schematics Collections are sets of named
schematics, that are published and installed by
users.
Angular team publishes and maintains the official
@schematics/angular collection e.g component,
module, application
Scenario: add some disclaimer text on top of
component
We start by scaffolding a project
schematics blank --name=my-external
We need to add two new helper functions:
chain, is a RuleFactory provided by Schematics
library, chains multiple rules together
externalSchematic, also a rule factory
import {
Rule,
SchematicContext,
Tree,
chain,
externalSchematic } from '@angular-devkit/schematics';
install @schematics/angular
imports and runs the schematic
externalSchematic('@schematics/angular', 'component', options)
Next part is our schematic that needs to
go through all files
for each file list it's content and add header text
const headerText = `
@copyright ngVikings, by the community, for the community
`
(tree: Tree, _context: SchematicContext) => {
tree.getDir(options.sourceDir)
.visit(filePath => {
if (!filePath.endsWith('.ts')) {
return;
}
const content = tree.read(filePath);
if (!content) {
return;
}
// Prevent from writing license to files that already ha
if (content.indexOf(licenseText) == -1) {
tree.overwrite(filePath, headerText + content);
}
Building and running the above
Angular Schematics
A scaffolded component
with our header text in place
EXAMPLEEXAMPLE
SCAFFOLD BASED ON TEMPLATESSCAFFOLD BASED ON TEMPLATES
We want to:
define scaffold files
define templates
replace template content with commandline args
Scaffold a new blank project
schematics blank --name=my-template
define template file
you can place them where you want but your
tsconfig.json is set to ignore /files
let's create some template files
Angular Schematics
we are looking to replace name
<%= name %>
let's write some code
export function myTemplate(_options: any): Rule {
_options.path = _options.path ? normalize(_options.path) : _
const templateSource = apply(url("./files"), [
filterTemplates(_options),
template({
...stringUtils,
..._options
}),
move("/src/app/my-template")
// what to do with the files in here
]);
return chain([branchAndMerge(chain([mergeWith(templateSource
}
let's break it down
filterTemplates, function that ensures we get the
template files we want
template, function that takes a template and
content and merge them
move, where we place the end result
if service is NOT specified as command line arg, then
we don't include it else just filter out .bak files
function filterTemplates(options: any): Rule {
if (!options.service) {
return filter(
path =>
!path.match(/.service.ts$/) &&
!path.match(/-item.ts/) &&
!path.match(/.bak$/)
);
}
return filter(path => !path.match(/.bak$/));
}
stringUtils obj containing helper functions for our
template, e.g classify _options obj containing
data that we want to pass to our template, e.g name
template({
...stringUtils,
..._options
})
let's update our template
classify comes from stringUtils, ensures we
get capital letter name name from _options
export class <%= classify(name) %> {
getData() {
// fetch data here
}
}
looking at end result
Angular Schematics
THE ANATOMY OF A TREETHE ANATOMY OF A TREE
is a list of type Action
let's look at what an Action is
tree.actions // Action[]
different type of actions,
path looks interesting
kind is a property that says what type of CRUD
export declare type Action =
CreateFileAction |
OverwriteFileAction |
RenameFileAction |
DeleteFileAction;
export interface ActionBase {
readonly id: number;
readonly parent: number;
readonly path: Path;
}
ok, an Action seems to represent our intent, how do
we read from it?
tree.actions.forEach(action => {
console.log("action kind", action.kind);
console.log("action path", action.path);
let fe = tree.get(action.path);
if (fe) {
console.log("action content", fe.content.toString("utf8"))
}
});
ok so we can list all the things the tree is about to do,
with its content
This is internals, it might change in the near future, still
interesting though
UNDERSTANDING YOUR CODEUNDERSTANDING YOUR CODE
USING THE TYPESCRIPT COMPILERUSING THE TYPESCRIPT COMPILER
We can send in our code into the Typescript compiler
and it will give us a tree representation back
read file
convert file content into a SourceFile
investigate your tree
very simple file
class DemoClass {
constructor(otherDemo: DemoClass, param: string) {}
}
read, create source file
let node = ts.createSourceFile(
'demo.ts',
content,
ts.ScriptTarget.Latest,
true
);
let's try to print our nodes in a nice way
thank you Manfred Steyer for this function
function showTree(node: ts.Node, indent: string = ' '): voi
console.log(indent + ts.SyntaxKind[node.kind]);
if (node.getChildCount() === 0) {
console.log(indent + ' Text: ' + node.getText());
}
for(let child of node.getChildren()) {
showTree(child, indent + ' ');
}
}
showTree(node);
Angular Schematics
TODO show tree content
What about changing the tree?
we need to flatten the tree into a list of nodes, for
convenience
we need to find the correct position to do our
change
we need to create a Change object that says path,
position of change and with what
content
lastly we need to call the following on the tree
beginUpdate, to get a recorder commitUpdate
to make the changes stick
admire our work
gives us a flattened list of Nodes
const nodes = getSourceNodes(componentSource);
you can query nodes by type, find the type you need
according to our AST tree
function getNodeByType(nodes: ts.Node[], type: ts.SyntaxKind)
return nodes.find(n => n.kind === type)[0];
}
// e.g
const node = getNodeByType(
nodes,
ts.SyntaxKind.ConstructorKeyword
)
once you have the correct node, simply insert
before/a er your node
function createChange(path: any, what: string, pos: number) {
return new InsertChange(path, pos, what);
}
createChange('path-to-file', 'insert this', node.pos+1)
interate our list of changes and commit/ save
function applyChanges(path: string, content: string, changes:
tree.create(path, content);
const exportRecorder = tree.beginUpdate(path);
for (const change of changes) {
if (change instanceof InsertChange) {
exportRecorder.insertLeft(change.pos, change.toAdd);
}
}
tree.commitUpdate(exportRecorder);
}
all together now :)
function myRule(options): Rule {
return (tree: Tree, _context: SchematicContext) => {
const componentSource = getTsSource( componentPath,
componentContent
);
const nodes = getSourceNodes(componentSource);
const node = getNodeByType( nodes,
ts.SyntaxKind.ConstructorKeyword
);
const change = createChange( componentPath,
'insert this',
node.pos+1
);
applyChanges( componentPath,
componentContent, [ change ], tree);
FURTHER READINGFURTHER READING
Intro article to Schematics article by Hans from Angula
https://blog.angular.io/schematics-an-introduction-
dc1dfbc2a2b2
Manfred Steyer, 5 blog post series,
https://www.so warearchitekt.at/post/2017/10/29/ge
custom-code-with-the-angular-cli-and-schematics.asp
Manfred Steyer, free book on Schematics,
https://leanpub.com/angular-schematics
Jorge Cano, article, https://medium.com/@jorgeucan
fist-angular-schematics-f711d70cb37c
SUMMARYSUMMARY
Workflow tool
Performs changes on a Tree
Consist of Rules you apply on a Tree
Can be used for scaffolding but also update code
is the secret sauce behind Angular-CLI
THANK YOUTHANK YOU

More Related Content

What's hot (20)

PDF
Cluster-as-code. The Many Ways towards Kubernetes
QAware GmbH
 
PDF
Conférence: Catalyseurs de l'Intelligence Artificielle et Écosystème des Fram...
ENSET, Université Hassan II Casablanca
 
PDF
Automation with ansible
Khizer Naeem
 
PDF
Docker and WASM
Antonis Kalipetis
 
PDF
Seamless scaling of Kubernetes nodes
Marko Bevc
 
PDF
TMUX Rocks!
Kent Chen
 
PDF
Coder sans peur du changement avec la meme pas mal hexagonal architecture
Thomas Pierrain
 
PDF
클라우드의 대세 쿠버네티스란 무엇인가?(윤성훈 클라우드 솔루션 아키텍트) - Webinar
NAVER CLOUD PLATFORMㅣ네이버 클라우드 플랫폼
 
PDF
Introduction to Red Hat OpenShift 4
HngNguyn748044
 
PDF
OpenStack 개요 및 활용 사례 @ Community Open Camp with Microsoft
Ian Choi
 
PDF
Building Network Functions with eBPF & BCC
Kernel TLV
 
PDF
Reactive Microservices with Quarkus
Niklas Heidloff
 
PDF
Scheduling in Android
Opersys inc.
 
PDF
Terraforming your Infrastructure on GCP
Samuel Chow
 
PDF
Alexei Vladishev - Zabbix - Monitoring Solution for Everyone
Zabbix
 
PDF
Support NodeJS avec TypeScript Express MongoDB
ENSET, Université Hassan II Casablanca
 
PPTX
Networking in Openstack - Neutron 101
Mochamad Taufik Romdony
 
PDF
HKG18- 115 - Partitioning ARM Systems with the Jailhouse Hypervisor
Linaro
 
PPT
APACHE HTTP
Rachid NID SAID
 
PDF
QEMU Disk IO Which performs Better: Native or threads?
Pradeep Kumar
 
Cluster-as-code. The Many Ways towards Kubernetes
QAware GmbH
 
Conférence: Catalyseurs de l'Intelligence Artificielle et Écosystème des Fram...
ENSET, Université Hassan II Casablanca
 
Automation with ansible
Khizer Naeem
 
Docker and WASM
Antonis Kalipetis
 
Seamless scaling of Kubernetes nodes
Marko Bevc
 
TMUX Rocks!
Kent Chen
 
Coder sans peur du changement avec la meme pas mal hexagonal architecture
Thomas Pierrain
 
클라우드의 대세 쿠버네티스란 무엇인가?(윤성훈 클라우드 솔루션 아키텍트) - Webinar
NAVER CLOUD PLATFORMㅣ네이버 클라우드 플랫폼
 
Introduction to Red Hat OpenShift 4
HngNguyn748044
 
OpenStack 개요 및 활용 사례 @ Community Open Camp with Microsoft
Ian Choi
 
Building Network Functions with eBPF & BCC
Kernel TLV
 
Reactive Microservices with Quarkus
Niklas Heidloff
 
Scheduling in Android
Opersys inc.
 
Terraforming your Infrastructure on GCP
Samuel Chow
 
Alexei Vladishev - Zabbix - Monitoring Solution for Everyone
Zabbix
 
Support NodeJS avec TypeScript Express MongoDB
ENSET, Université Hassan II Casablanca
 
Networking in Openstack - Neutron 101
Mochamad Taufik Romdony
 
HKG18- 115 - Partitioning ARM Systems with the Jailhouse Hypervisor
Linaro
 
APACHE HTTP
Rachid NID SAID
 
QEMU Disk IO Which performs Better: Native or threads?
Pradeep Kumar
 

Similar to Angular Schematics (20)

PDF
Sbt for mere mortals
Ivan Porto Carrero
 
PPT
Svcc Building Rich Applications with Groovy's SwingBuilder
Andres Almiray
 
PDF
Scala4sling
day
 
PDF
ZendCon2010 The Doctrine Project
Jonathan Wage
 
PDF
Ejb3 Struts Tutorial En
Ankur Dongre
 
PDF
Ejb3 Struts Tutorial En
Ankur Dongre
 
PDF
The use of the code analysis library OpenC++: modifications, improvements, er...
PVS-Studio
 
PDF
Fun Teaching MongoDB New Tricks
MongoDB
 
PDF
Nosql hands on handout 04
Krishna Sankar
 
PDF
Intake 37 ef2
Mahmoud Ouf
 
PDF
Uncommon Design Patterns
Stefano Fago
 
PPT
Smoothing Your Java with DSLs
intelliyole
 
PPTX
A brief overview of java frameworks
MD Sayem Ahmed
 
PPTX
Ian 2014.10.24 weekly report
LearningTech
 
PDF
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
Bill Buchan
 
PPT
iOS Application Development
Compare Infobase Limited
 
PPT
Groovy Introduction - JAX Germany - 2008
Guillaume Laforge
 
PPSX
ASP.Net Presentation Part2
Neeraj Mathur
 
PDF
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...
ICS User Group
 
PDF
From HelloWorld to Configurable and Reusable Apache Spark Applications in Sca...
Databricks
 
Sbt for mere mortals
Ivan Porto Carrero
 
Svcc Building Rich Applications with Groovy's SwingBuilder
Andres Almiray
 
Scala4sling
day
 
ZendCon2010 The Doctrine Project
Jonathan Wage
 
Ejb3 Struts Tutorial En
Ankur Dongre
 
Ejb3 Struts Tutorial En
Ankur Dongre
 
The use of the code analysis library OpenC++: modifications, improvements, er...
PVS-Studio
 
Fun Teaching MongoDB New Tricks
MongoDB
 
Nosql hands on handout 04
Krishna Sankar
 
Intake 37 ef2
Mahmoud Ouf
 
Uncommon Design Patterns
Stefano Fago
 
Smoothing Your Java with DSLs
intelliyole
 
A brief overview of java frameworks
MD Sayem Ahmed
 
Ian 2014.10.24 weekly report
LearningTech
 
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
Bill Buchan
 
iOS Application Development
Compare Infobase Limited
 
Groovy Introduction - JAX Germany - 2008
Guillaume Laforge
 
ASP.Net Presentation Part2
Neeraj Mathur
 
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...
ICS User Group
 
From HelloWorld to Configurable and Reusable Apache Spark Applications in Sca...
Databricks
 
Ad

More from Christoffer Noring (20)

PPTX
Azure signalR
Christoffer Noring
 
PPTX
Game dev 101 part 3
Christoffer Noring
 
PPTX
Game dev 101 part 2
Christoffer Noring
 
PPTX
Game dev workshop
Christoffer Noring
 
PPTX
Deploying your static web app to the Cloud
Christoffer Noring
 
PPTX
IaaS with ARM templates for Azure
Christoffer Noring
 
PPTX
Learning Svelte
Christoffer Noring
 
PPTX
Ng spain
Christoffer Noring
 
PDF
Design thinking
Christoffer Noring
 
PDF
Keynote ijs
Christoffer Noring
 
PDF
Vue fundamentasl with Testing and Vuex
Christoffer Noring
 
PDF
Ngrx slides
Christoffer Noring
 
PDF
Kendoui
Christoffer Noring
 
PPTX
Angular mix chrisnoring
Christoffer Noring
 
PDF
Nativescript angular
Christoffer Noring
 
PDF
Graphql, REST and Apollo
Christoffer Noring
 
PDF
Angular 2 introduction
Christoffer Noring
 
PDF
Rxjs vienna
Christoffer Noring
 
PPTX
Rxjs marble-testing
Christoffer Noring
 
PDF
React lecture
Christoffer Noring
 
Azure signalR
Christoffer Noring
 
Game dev 101 part 3
Christoffer Noring
 
Game dev 101 part 2
Christoffer Noring
 
Game dev workshop
Christoffer Noring
 
Deploying your static web app to the Cloud
Christoffer Noring
 
IaaS with ARM templates for Azure
Christoffer Noring
 
Learning Svelte
Christoffer Noring
 
Design thinking
Christoffer Noring
 
Keynote ijs
Christoffer Noring
 
Vue fundamentasl with Testing and Vuex
Christoffer Noring
 
Ngrx slides
Christoffer Noring
 
Angular mix chrisnoring
Christoffer Noring
 
Nativescript angular
Christoffer Noring
 
Graphql, REST and Apollo
Christoffer Noring
 
Angular 2 introduction
Christoffer Noring
 
Rxjs vienna
Christoffer Noring
 
Rxjs marble-testing
Christoffer Noring
 
React lecture
Christoffer Noring
 
Ad

Recently uploaded (20)

PDF
Transforming Utility Networks: Large-scale Data Migrations with FME
Safe Software
 
PDF
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
PPTX
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
PDF
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
PDF
The 2025 InfraRed Report - Redpoint Ventures
Razin Mustafiz
 
PDF
NASA A Researcher’s Guide to International Space Station : Physical Sciences ...
Dr. PANKAJ DHUSSA
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PDF
SIZING YOUR AIR CONDITIONER---A PRACTICAL GUIDE.pdf
Muhammad Rizwan Akram
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PDF
“Squinting Vision Pipelines: Detecting and Correcting Errors in Vision Models...
Edge AI and Vision Alliance
 
PPTX
Designing_the_Future_AI_Driven_Product_Experiences_Across_Devices.pptx
presentifyai
 
PDF
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
DOCX
Python coding for beginners !! Start now!#
Rajni Bhardwaj Grover
 
PPTX
Future Tech Innovations 2025 – A TechLists Insight
TechLists
 
PDF
“Voice Interfaces on a Budget: Building Real-time Speech Recognition on Low-c...
Edge AI and Vision Alliance
 
DOCX
Cryptography Quiz: test your knowledge of this important security concept.
Rajni Bhardwaj Grover
 
PDF
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
PDF
Kit-Works Team Study_20250627_한달만에만든사내서비스키링(양다윗).pdf
Wonjun Hwang
 
PDF
AI Agents in the Cloud: The Rise of Agentic Cloud Architecture
Lilly Gracia
 
PPTX
Digital Circuits, important subject in CS
contactparinay1
 
Transforming Utility Networks: Large-scale Data Migrations with FME
Safe Software
 
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
The 2025 InfraRed Report - Redpoint Ventures
Razin Mustafiz
 
NASA A Researcher’s Guide to International Space Station : Physical Sciences ...
Dr. PANKAJ DHUSSA
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
SIZING YOUR AIR CONDITIONER---A PRACTICAL GUIDE.pdf
Muhammad Rizwan Akram
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
“Squinting Vision Pipelines: Detecting and Correcting Errors in Vision Models...
Edge AI and Vision Alliance
 
Designing_the_Future_AI_Driven_Product_Experiences_Across_Devices.pptx
presentifyai
 
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
Python coding for beginners !! Start now!#
Rajni Bhardwaj Grover
 
Future Tech Innovations 2025 – A TechLists Insight
TechLists
 
“Voice Interfaces on a Budget: Building Real-time Speech Recognition on Low-c...
Edge AI and Vision Alliance
 
Cryptography Quiz: test your knowledge of this important security concept.
Rajni Bhardwaj Grover
 
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
Kit-Works Team Study_20250627_한달만에만든사내서비스키링(양다윗).pdf
Wonjun Hwang
 
AI Agents in the Cloud: The Rise of Agentic Cloud Architecture
Lilly Gracia
 
Digital Circuits, important subject in CS
contactparinay1
 

Angular Schematics

  • 2. CHRIS NORINGCHRIS NORING CLOUD DEVELOPER EXPERT AT MICROSOFTCLOUD DEVELOPER EXPERT AT MICROSOFT Google Developer Expert in Angular and Web Techs @chris_noring https://so chris.github.io Published author Public Speaker So ware Engineer
  • 3. WORKFLOW TOOLWORKFLOW TOOL CAN APPLY TRANSFORMS TO YOUR PROJECTCAN APPLY TRANSFORMS TO YOUR PROJECT example of usage: scaffold: new components, services, update your code to fix breaking changes in dependencies. or add a new configuration option or framework to an existing project
  • 4. ANGULAR CLI - SECRET SAUCEANGULAR CLI - SECRET SAUCE GENERIC FACILITY TO SUPPORT THE CLIGENERIC FACILITY TO SUPPORT THE CLI SCAFFOLDINGSCAFFOLDING improve your development productivity Ease uf use and development Extensibility and reuseability Atomicity Asynchronicity
  • 5. TREETREE OVER FILE SYSTEMOVER FILE SYSTEM not affecting the file system directly, you describe what transformations you want done on a Tree
  • 6. INSTALLATIONINSTALLATION npm install -g @angular-devkit/schematics-cli This will install a schematics executable, which you can use to create a blank Schematics project
  • 10. index.ts, where our rules live collection.json, a description of our project
  • 11. INDEX.TSINDEX.TS return a function of type Rule options input, is an object representing command line args inner function takes Tree and SchematicContext, tree is file tree
  • 13. COLLECTION.JSONCOLLECTION.JSON description, description of project factory, points to the directory/starter module
  • 15. BUILD AND RUNBUILD AND RUN --name=test, command line arg npm run build schematics .:my-component --name=test
  • 16. it says: nothing to be done!!
  • 17. not surprised, cause our Rule factory function does nothing
  • 18. EXAMPLEEXAMPLE SCAFFOLD SOME FILES, WITH CONTENTSCAFFOLD SOME FILES, WITH CONTENT
  • 20. create files, with content tree.create(filename, file-content)
  • 21. let's create a build and run script
  • 24. we didn't actual create any files, we are in dry-run mode It shows what would happen if applied to a file system
  • 25. let's shut off dry-run
  • 26. I don't see a difference??
  • 27. oh, so they were created in the in the project
  • 28. Just add the follwing to your schematics executable --dry-run=false
  • 29. There are four methods that directly create a change in a Tree create delete rename overwrite
  • 30. TIPS AND TRICKSTIPS AND TRICKS
  • 31. watch mode, rebuild your project on changes npm run build -w
  • 33. TESTING OUT YOUR SCHEMATICSTESTING OUT YOUR SCHEMATICS
  • 34. scaffold an Angular project npm link to the schematics ng generate
  • 36. npm link <path to schematics> // tip: run pwd and copy result
  • 39. Voila, our Vikings are added
  • 40. EXAMPLEEXAMPLE USING AN EXISTING SCHEMATICUSING AN EXISTING SCHEMATIC
  • 41. WHAT IS A COLLECTION?WHAT IS A COLLECTION? Schematics Collections are sets of named schematics, that are published and installed by users. Angular team publishes and maintains the official @schematics/angular collection e.g component, module, application
  • 42. Scenario: add some disclaimer text on top of component
  • 43. We start by scaffolding a project schematics blank --name=my-external
  • 44. We need to add two new helper functions: chain, is a RuleFactory provided by Schematics library, chains multiple rules together externalSchematic, also a rule factory
  • 46. install @schematics/angular imports and runs the schematic externalSchematic('@schematics/angular', 'component', options)
  • 47. Next part is our schematic that needs to go through all files for each file list it's content and add header text
  • 48. const headerText = ` @copyright ngVikings, by the community, for the community `
  • 49. (tree: Tree, _context: SchematicContext) => { tree.getDir(options.sourceDir) .visit(filePath => { if (!filePath.endsWith('.ts')) { return; } const content = tree.read(filePath); if (!content) { return; } // Prevent from writing license to files that already ha if (content.indexOf(licenseText) == -1) { tree.overwrite(filePath, headerText + content); }
  • 50. Building and running the above
  • 53. with our header text in place
  • 54. EXAMPLEEXAMPLE SCAFFOLD BASED ON TEMPLATESSCAFFOLD BASED ON TEMPLATES
  • 55. We want to: define scaffold files define templates replace template content with commandline args
  • 56. Scaffold a new blank project
  • 58. define template file you can place them where you want but your tsconfig.json is set to ignore /files
  • 59. let's create some template files
  • 61. we are looking to replace name <%= name %>
  • 63. export function myTemplate(_options: any): Rule { _options.path = _options.path ? normalize(_options.path) : _ const templateSource = apply(url("./files"), [ filterTemplates(_options), template({ ...stringUtils, ..._options }), move("/src/app/my-template") // what to do with the files in here ]); return chain([branchAndMerge(chain([mergeWith(templateSource }
  • 64. let's break it down filterTemplates, function that ensures we get the template files we want template, function that takes a template and content and merge them move, where we place the end result
  • 65. if service is NOT specified as command line arg, then we don't include it else just filter out .bak files function filterTemplates(options: any): Rule { if (!options.service) { return filter( path => !path.match(/.service.ts$/) && !path.match(/-item.ts/) && !path.match(/.bak$/) ); } return filter(path => !path.match(/.bak$/)); }
  • 66. stringUtils obj containing helper functions for our template, e.g classify _options obj containing data that we want to pass to our template, e.g name template({ ...stringUtils, ..._options })
  • 67. let's update our template
  • 68. classify comes from stringUtils, ensures we get capital letter name name from _options export class <%= classify(name) %> { getData() { // fetch data here } }
  • 69. looking at end result
  • 71. THE ANATOMY OF A TREETHE ANATOMY OF A TREE
  • 72. is a list of type Action let's look at what an Action is tree.actions // Action[]
  • 73. different type of actions, path looks interesting kind is a property that says what type of CRUD export declare type Action = CreateFileAction | OverwriteFileAction | RenameFileAction | DeleteFileAction; export interface ActionBase { readonly id: number; readonly parent: number; readonly path: Path; }
  • 74. ok, an Action seems to represent our intent, how do we read from it?
  • 75. tree.actions.forEach(action => { console.log("action kind", action.kind); console.log("action path", action.path); let fe = tree.get(action.path); if (fe) { console.log("action content", fe.content.toString("utf8")) } });
  • 76. ok so we can list all the things the tree is about to do, with its content
  • 77. This is internals, it might change in the near future, still interesting though
  • 78. UNDERSTANDING YOUR CODEUNDERSTANDING YOUR CODE USING THE TYPESCRIPT COMPILERUSING THE TYPESCRIPT COMPILER
  • 79. We can send in our code into the Typescript compiler and it will give us a tree representation back
  • 80. read file convert file content into a SourceFile investigate your tree
  • 81. very simple file class DemoClass { constructor(otherDemo: DemoClass, param: string) {} }
  • 82. read, create source file let node = ts.createSourceFile( 'demo.ts', content, ts.ScriptTarget.Latest, true );
  • 83. let's try to print our nodes in a nice way
  • 84. thank you Manfred Steyer for this function function showTree(node: ts.Node, indent: string = ' '): voi console.log(indent + ts.SyntaxKind[node.kind]); if (node.getChildCount() === 0) { console.log(indent + ' Text: ' + node.getText()); } for(let child of node.getChildren()) { showTree(child, indent + ' '); } } showTree(node);
  • 86. TODO show tree content
  • 87. What about changing the tree?
  • 88. we need to flatten the tree into a list of nodes, for convenience we need to find the correct position to do our change we need to create a Change object that says path, position of change and with what content lastly we need to call the following on the tree beginUpdate, to get a recorder commitUpdate to make the changes stick admire our work
  • 89. gives us a flattened list of Nodes const nodes = getSourceNodes(componentSource);
  • 90. you can query nodes by type, find the type you need according to our AST tree function getNodeByType(nodes: ts.Node[], type: ts.SyntaxKind) return nodes.find(n => n.kind === type)[0]; } // e.g const node = getNodeByType( nodes, ts.SyntaxKind.ConstructorKeyword )
  • 91. once you have the correct node, simply insert before/a er your node function createChange(path: any, what: string, pos: number) { return new InsertChange(path, pos, what); } createChange('path-to-file', 'insert this', node.pos+1)
  • 92. interate our list of changes and commit/ save function applyChanges(path: string, content: string, changes: tree.create(path, content); const exportRecorder = tree.beginUpdate(path); for (const change of changes) { if (change instanceof InsertChange) { exportRecorder.insertLeft(change.pos, change.toAdd); } } tree.commitUpdate(exportRecorder); }
  • 93. all together now :) function myRule(options): Rule { return (tree: Tree, _context: SchematicContext) => { const componentSource = getTsSource( componentPath, componentContent ); const nodes = getSourceNodes(componentSource); const node = getNodeByType( nodes, ts.SyntaxKind.ConstructorKeyword ); const change = createChange( componentPath, 'insert this', node.pos+1 ); applyChanges( componentPath, componentContent, [ change ], tree);
  • 94. FURTHER READINGFURTHER READING Intro article to Schematics article by Hans from Angula https://blog.angular.io/schematics-an-introduction- dc1dfbc2a2b2 Manfred Steyer, 5 blog post series, https://www.so warearchitekt.at/post/2017/10/29/ge custom-code-with-the-angular-cli-and-schematics.asp Manfred Steyer, free book on Schematics, https://leanpub.com/angular-schematics Jorge Cano, article, https://medium.com/@jorgeucan fist-angular-schematics-f711d70cb37c
  • 95. SUMMARYSUMMARY Workflow tool Performs changes on a Tree Consist of Rules you apply on a Tree Can be used for scaffolding but also update code is the secret sauce behind Angular-CLI