@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
{
today: {
temperatures: [19, 18.5, 18, 18.5, 17, /* ... */]
},
future: [
{ high: 21, low: 13, chanceOfSnow: 0.05 },
{ high: 21, low: 14, chanceOfSnow: 0.03 },
{ high: 21, low: 16, chanceOfSnow: 0.04 },
{ high: 19, low: 16, chanceOfSnow: 0.04 },
/* ... */
]
}
@phenomnominal 2019
<h2>Weather result</h2>
<h3>
<p>Arendelle, Norway</p>
<p>Sunday 19:00</p>
<span>Sunny</span>
</h3>
<img alt="Sunny" src="//arendelle.info/weather/64/sunny.png">
<h3>
19<button aria-label="°Celsius">°C</button>
</h3>
<p>Precipitation: <span>0%</span></p>
<p>Humidity: <span>75%</span></p>
<p>Wind: <span>1 m/s</span></p>
<ol>
<li>
<p aria-label="Sunday">Sun</p>
<img alt="Clear" src="//arendelle.info/weather/48/sunny.png">
<span>21</span>°
<span>13</span>°
</li>
<!-- ... -->
</ol>
@phenomnominal 2019
const response = await fetch('https://arendelle.info/weather.json');
const data = await response.json();
// {
// today: {
// temperatures: [19, 18.5, 18, 18.5, 17, /* ... */]
// },
// future: [
// { high: 21, low: 13, chanceOfSnow: 0.05 },
// { high: 21, low: 14, chanceOfSnow: 0.03 },
// { high: 21, low: 16, chanceOfSnow: 0.04 },
// { high: 19, low: 16, chanceOfSnow: 0.04 },
// /* ... */
// ]
// }
const SATURDAY = 6;
const today = new Date().getDay();
const chanceOfSnowOnSaturday = data.future[SATURDAY - today].chanceOfSnow * 100;
h1 {
// ...
}
h3 > p {
// ...
}
button:active,
button:hover {
// ...
}
li:first-child {
// ...
}
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
fs.watch
fs.link
fs.copyFile
fs.chmod
fs.access
@phenomnominal 2019
fs.writeFile
fs.mkdir
fs.readFile
@phenomnominal 2019
// snowflake.txt
()
/\
//\\
<< >>
() \\// ()
()._____ /\ \\ /\ _____.()
\.--.\ //\\ //\\ //\\ /.--./
\\__\\/__\//__\//__\\/__//
'--/\\--//\--//\--/\\--'
\\\\///\\//\\\////
()-= >>\\< <\\> >\\<< =-()
////\\\//\\///\\\\
.--\\/--\//--/\\--/\\--.
//""/\\""//\""//\""//\""\\
/'--'/ \\// \\// \\// \'--'\
()`"""` \/ // \/ `"""`()
() //\\ ()
<< >>
\\//
\/
()
@phenomnominal 2019
import * as fs from 'fs';
async function main () {
console.log(await readSnowflake());
};
async function readSnowflake (): Promise<string> {
return fs.promises.readFile('./snowflake.txt', 'utf8');
}
main();
@phenomnominal 2019
Weaseltown:dywbabt queenelsa$ ts-node index.ts
()
/\
//\\
<< >>
() \\// ()
()._____ /\ \\ /\ _____.()
\.--.\ //\\ //\\ //\\ /.--./
\\__\\/__\//__\//__\\/__//
'--/\\--//\--//\--/\\--'
\\\\///\\//\\\////
()-= >>\\< <\\> >\\<< =-()
////\\\//\\///\\\\
.--\\/--\//--/\\--/\\--.
//""/\\""//\""//\""//\""\\
/'--'/ \\// \\// \\// \'--'\
()`"""` \/ // \/ `"""`()
() //\\ ()
<< >>
\\//
\/
()
@phenomnominal 2019
import * as fs from 'fs';
async function main () {
const snowflake = await readSnowflake();
await saveSnowflake(snowflake);
};
async function readSnowflake (): Promise<string> {
return fs.promises.readFile('./snowflake.txt', 'utf8');
}
async function saveSnowflake (data: string): Promise<void> {
await fs.promises.mkdir('./saved/snowflakes', { recursive: true });
await fs.promises.writeFile('./saved/snowflakes/snowflake.txt', data);
}
main();
@phenomnominal 2019
path.resolve
path.parse
@phenomnominal 2019
import * as path from 'path';
const relativeToThisFile = path.resolve(__dirname, './snowflake.txt');
const parsed = path.parse(relativeToThisFile);
// interface ParsedPath {
// root: string;
// dir: string;
// base: string;
// ext: string;
// name: string;
// }
import * as fs from 'fs';
import * as path from 'path';
export async function readSnowflake (): Promise<string> {
const relativePath = path.resolve(__dirname, './snowflake.txt');
const relativePath = path.resolve(process.cwd(), './snowflake.txt');
return fs.promises.readFile(relativePath, 'utf8');
}
@phenomnominal 2019
import * as glob from 'fast-glob';
(async function () {
const entries = await glob('./src/**/*.ts');
console.log(entries);
// ['./src/path/to/a/file.ts', './src/path/to/another/file.ts']
})();
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
import * as fs from 'fs';
import * as path from 'path';
async function main () {
console.log(await readSnowflakes());
}
async function readSnowflakes (): Promise<Array<WaterMolecule>> {
const snowflakePath = path.resolve(__dirname, './snowflakes.json');
const json = await fs.promises.readFile(snowflakePath, 'utf8');
return JSON.parse(json);
}
main();
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
const SNOW_CODE_PATH = path.resolve(
__dirname,
'./elsa',
process.env.SECRET_SNOW_FILE
);
@phenomnominal 2019
const SNOW_CODE_PATH = path.resolve(
__dirname,
'./elsa',
process.env.SECRET_SNOW_FILE
);
@phenomnominal 2019
@phenomnominal 2019
import * as fs from 'fs';
async function main () {
console.log(await readSnowCode());
};
export async function readSnowCode (): Promise<string> {
return fs.promises.readFile(SNOW_CODE_PATH, 'utf8');
}
main();
@phenomnominal 2019
Weaseltown:dywbabt queenelsa$ ts-node index.ts
import { doPhysics, WaterMolecule } from './physics';
requestAnimationFrame(() => {
for (let lat = -90; lat < 90; lat += 0.000000001) {
for (let long = -180; long < 180; long += 0.000000001) {
for (let alt = 0; alt < 80000; alt += 0.000000001) {
const updated = update(lat, long, alt);
render(updated);
}
}
}
});
function update (lat: number, long: number, alt: number): WaterMolecule {
const molecule = global.waterMolecules[lat][long][alt];
return doPhysics(molecule);
}
@phenomnominal 2019
@phenomnominal 2019
// kristoff.ts
import * as fs from 'fs';
import { readSnowCode } from './read-snow-code';
(async function () {
const code = await readSnowCode();
code += `; console.log('Kristoff is the best!');`
return fs.writeFile('./kristoffs-cool-new-snow-code.ts', code);
})();
@phenomnominal 2019
// olaf.ts
import * as fs from 'fs';
(async function () {
const code = await fs.readFile('./kristoffs-cool-new-snow-code.ts');
code = code.replace(/Kristoff/, 'Olaf');
return fs.writeFile('./kristoffs-cool-new-snow-code.ts', code);
})();
@phenomnominal 2019
// sven.ts
import * as fs from 'fs';
(async function () {
const code = await fs.readFile('./kristoffs-cool-new-snow-code.ts');
code = code.replace(/Olaf/, 'Sven');
code = code.replace(/best!/, 'bestest!!!!');
code = code.replace(/console.log\((.*)\)/, 'console.log($1.toUpperCase())');
return fs.writeFile('./kristoffs-cool-new-snow-code.ts', code);
})();
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
import * as path from 'path';
const parsed = path.parse('/some/path/to/some/file.txt');
// interface ParsedPath {
// root: string;
// dir: string;
// base: string;
// ext: string;
// name: string;
// }
console.log(parsed.ext);
// read-snowflakes.ts
import * as fs from 'fs';
import * as path from 'path';
export async function readSnowflakes (): Promise<Array<WaterMolecule>> {
const snowflakePath = path.resolve(__dirname, './snowflakes.json');
const data = await fs.promises.readFile(snowflakePath, 'utf8');
const snowflakes = JSON.parse(data);
console.log(snowFlakes[0].velocity.x)
}
@phenomnominal 2019
import { createSourceFile, ScriptKind, ScriptTarget, SourceFile } from 'typescript';
import { readSnowCode } from './read-snow-code';
async function main () {
const code = await readSnowCode();
const ast = parse(code);
console.log(ast);
}
function parse (source: string): SourceFile {
return createSourceFile('', source, ScriptTarget.Latest, true, ScriptKind.TS);
}
main();
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
data structure made up of vertices and edges without any cycles
the way in which linguistic elements are put together
Not associated with any specific instance
@phenomnominal 2019
@phenomnominal 2019
An Abstract Syntax Tree is a data structure that represents the structure of code, but without any actual syntax.
let it = go('let it go');
it = go 'let it go'
it <= go ['let it go']
'let it go' -> go => it
@phenomnominal 2019
{
"kind": "Program",
"statements": [{
"kind": "VariableStatement",
"declarationList": {
"kind": "VariableDeclarationList",
"declarations": [{
"kind": "VariableDeclaration",
"name": {
"kind": "Identifier",
"text": "it"
},
"initializer": {
"kind": "CallExpression",
"expression": {
"kind": "Identifier",
"text": "go"
},
"arguments": [{
"kind": "StringLiteral",
"text": "let it go"
}]
}
}]
}
}],
}
@phenomnominal 2019
'let it go'
StringLiteral
Identifier
CallExpression
Identifier
VariableDeclaration
VariableDeclarationList
go
go('let it go')
it
it = go('let it go')
let it = go('let it go')
VariableStatement
let it = go('let it go');
@phenomnominal 2019
Identifier
IfStatement
ImportDeclaration
NumericLiteral
TrueKeyword
CallExpression
StringLiteral
ClassDeclaration
FunctionDeclaration
VariableDeclaration
FalseKeyword
NullKeyword
AnyKeyword
ForStatement
WhileStatement
DoStatement
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
import { createSourceFile, ScriptKind, ScriptTarget, SourceFile } from 'typescript';
function parse (source: string): SourceFile {
return createSourceFile('', source, ScriptTarget.Latest, true, ScriptKind.TS);
}
const code = `let it = go('let it go');`
const ast = parse(code);
const arg = ast.statements[0].declarationsList.declarations[0].initializer.arguments[0];
console.log(arg);
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
{
"kind": "document",
"children": [{
"kind": "h2",
"children": [{
"kind": "text",
"text": "Weather result"
}]
}, {
"kind": "h3",
"children": [{
"kind": "p",
"children": [{
"kind": "text",
"text": "Arendelle, Norway"
}]
}, {
"kind": "p",
"children": [{
"kind": "text",
"text": "Sunday 19:00"
}]
}, {
"kind": "span",
"children": [{
"kind": "text",
"text": "Sunny"
}]
}]
}, {
"kind": "img",
"alt": "Sunny",
"src": "//arendelle.info/weather/64/sunny.png"
}]
}
@phenomnominal 2019
@phenomnominal 2019
{
"kind": "document",
"children": [{
"kind": "h2",
"children": [{
"kind": "text",
"text": "Weather result"
}]
}, {
"kind": "h3",
"children": [{
"kind": "p",
"children": [{
"kind": "text",
"text": "Arendelle, Norway"
}]
}, {
"kind": "p",
"children": [{
"kind": "text",
"text": "Sunday 19:00"
}]
}, {
"kind": "span",
"children": [{
"kind": "text",
"text": "Sunny"
}]
}]
}, {
"kind": "img",
"alt": "Sunny",
"src": "//arendelle.info/weather/64/sunny.png"
}]
}
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
import { parse } from './parse-html';
const HTML = `
<h3>...</h3>
...
`;
const dom = parse(HTML);
const node = dom.children[1].children[3].children[0];
console.log(node);
@phenomnominal 2019
const dom = parse(HTML);
const node = $(dom, 'body > h3 > span:last-child');
console.log(node);
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
import { tsquery } from '@phenomnomnominal/tsquery';
const code = `let it = go('let it go');`;
const ast = tsquery.ast(code);
const query = 'CallExpression:has(Identifier[name="go"]) > StringLiteral';
const nodes = tsquery.query(ast, query);
console.log(nodes);
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
import { tsquery } from '@phenomnomnominal/tsquery';
const code = `Object.freeze()`;
const ast = tsquery.ast(code);
const query =
'CallExpression:has(PropertyAccessExpression[expression.text="Object"][name.text="freeze"])';
const nodes = tsquery.query(ast, query);
if (nodes.length !== 0) {
throw new Error(`Don't use Object.freeze!`);
}
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
import { doPhysics, WaterMolecule } from './physics';
requestAnimationFrame(() => {
for (let lat = -90; lat < 90; lat += 0.000000001) {
for (let long = -180; long < 180; long += 0.000000001) {
for (let alt = 0; alt < 80000; alt += 0.000000001) {
const updated = update(lat, long, alt);
render(updated);
}
}
}
});
function update (lat: number, long: number, alt: number): WaterMolecule {
const molecule = global.waterMolecules[lat][long][alt];
return doPhysics(molecule);
}
@phenomnominal 2019
import { tsquery } from '@phenomnomnominal/tsquery';
import { createCall, createIdentifier, createPrinter } from 'typescript';
import { readSnowCode } from './read-snow-code';
const PHYSICS_CALL_QUERY = 'CallExpression:has(Identifier[name="doPhysics"])';
(async function () {
const snowCode = await readSnowCode());
const ast = tsquery.ast(snowCode);
const doPhysicsCalls = tsquery.query(ast, PHYSICS_CALL_QUERY);
doPhysicsCalls.forEach(doPhysicsCall => {
doPhysicsCall.expression.name = 'doMagic';
doMagicCall = doPhysicsCall;
doMagicCall.arguments = [
createCall(
createIdentifier('doPhysics'),
null,
[createIdentifier('molecule')]
)
];
});
})();
@phenomnominal 2019
import { doPhysics, WaterMolecule } from './physics';
requestAnimationFrame(() => {
for (let lat = -90; lat < 90; lat += 0.000000001) {
for (let long = -180; long < 180; long += 0.000000001) {
for (let alt = 0; alt < 80000; alt += 0.000000001) {
const updated = update(lat, long, alt);
render(updated);
}
}
}
});
function update (lat: number, long: number, alt: number): WaterMolecule {
const molecule = global.waterMolecules[lat][long][alt];
return doMagic(doPhysics(molecule));
}
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
// function doMagic (molecule) {
// molecule.setTemperature(-10);
// return molecule;
// }
function createMagicFunction (ast) {
return createFunctionDeclaration(null, null, null,
createIdentifier('doMagic'), null,
[createParameter(null, null, null, createIdentifier('molecule'))],
null,
createBlock([
createExpressionStatement(
createCall(
createPropertyAccess(
createIdentifier('molecule'),
createIdentifier('setTemperature')
), null,
[createPrefix(SyntaxKind.MinusToken,createNumericLiteral('10'))]
)
),
createReturn(createIdentifier('molecule'))
])
)
}
@phenomnominal 2019
@phenomnominal 2019
const h2 = document.createElement('h2');
h2.innerText = 'Weather result';
const h3 = document.createElement('h3');
const p1 = document.createElement('p');
p1.innerText = 'Arendelle, Norway';
const p2 = document.createElement('p');
p2.innerText = 'Sunday 19:00';
const span = document.createElement('span');
span.innerText = 'Sunny';
h3.appendChild(p1);
h3.appendChild(p2);
h3.appendChild(span);
const img = document.createElement('img');
img.setAttribute('alt', 'Sunny');
img.setAttribute('src', '//arendelle.info/weather/64/sunny.png');
@phenomnominal 2019
const template = `
<h2>Weather result</h2>
<h3>
<p>{{ location }}</p>
<p>{{ time }}</p>
<span>{{ weather }}</span>
</h3>
<img
alt="{{ weather }}"
src="//arendelle.info/weather/64/{{ weather }}.png">
`;
render(template, {
location: 'Arendelle, Norway',
time: 'Sunday 19:00',
weather: 'Sunny'
});
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
import { tsquery } from '@phenomnomnomninal/tsquery';
import { tstemplate } from '@phenomnomnominal/tstemplate';
const DO_MAGIC_TEMPLATE = tstemplate.compile(`
function doMagic (molecule) {
molecule.setTemperature(-<%= temperature %>);
return molecule;
}
`);
function createMagicFunction () {
const doMagicAst = DO_MAGIC_TEMPLATE({
temperature: createNumericLiteral('10')
});
const [doMagicFunction] = tsquery.query(doMagicAst, 'FunctionDeclaration');
return doMagicFunction;
}
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
(async function () {
const snowCode = await readSnowCode();
const ast = tsquery.ast(snowCode);
const doPhysicsCalls = tsquery.query(ast,
'CallExpression:has(Identifier[name="doPhysics"])'
);
doPhysicsCalls.forEach(doPhysicsCall => {
doPhysicsCall.expression.name = 'doMagic';
doPhysicsCall.arguments = [createCall(
createIdentifier('doPhysics'), null, [createIdentifier('molecule')]
)];
});
const doMagicAst = tstemplate(`
function doMagic (molecule) {
molecule.setTemperature(-<%= temperature %>);
return molecule;
}
`, {
temperature: createNumericLiteral('10')
});
const [doMagicFunction] = tsquery.query(doMagicAst, 'FunctionDeclaration');
ast.statements.push(doMagicFunction);
await writeSnowCode(createPrinter().print(ast));
})();
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019
@phenomnominal 2019