Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions loaders/register-inner-components.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
const parse = require('@babel/parser').parse;
const traverse = require("@babel/traverse").default;

module.exports = function(source) {
module.exports = function (source) {
const injections = {};
const positions = [];
const ast = parse(source, {
sourceType: 'module',
plugins: ['classProperties', 'jsx']
plugins: ['classProperties', 'jsx', 'typescript']
});
traverse(ast, {
ClassMethod(path) {
if(path.node.key.name.startsWith('render')) {
if (path.node.key.name.startsWith('render')) {
traverse(path.node, {
JSXIdentifier(subpath) {
if(/^[A-Z]/.test(subpath.node.name)) {
if(!path.scope.hasBinding(subpath.node.name)) {
if (/^[A-Z]/.test(subpath.node.name)) {
if (!path.scope.hasBinding(subpath.node.name)) {
const start = path.node.body.body[0].start;
if(!positions.includes(start)) {
if (!positions.includes(start)) {
positions.push(start);
}
if(!injections[start]) {
if (!injections[start]) {
injections[start] = [];
}
if(!injections[start].includes(subpath.node.name)) {
if (!injections[start].includes(subpath.node.name)) {
injections[start].push(subpath.node.name);
}
}
Expand All @@ -36,13 +36,13 @@ module.exports = function(source) {
positions.push(0);
let outputs = [];
let last;
for(const position of positions) {
for (const position of positions) {
let code = source.slice(position, last);
last = position;
outputs.push(code);
if(position) {
for(const injection of injections[position]) {
if(injection) {
if (position) {
for (const injection of injections[position]) {
if (injection) {
outputs.push(`const ${injection} = this.render${injection};\n `)
}
}
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
"bin": {
"nullstack": "./scripts/index.js"
},
"types": "./types/index.d.ts",
"dependencies": {
"@babel/plugin-transform-typescript": "^7.16.1",
"typescript": "^4.5.3",
"ts-loader": "^9.2.6",
"@babel/cli": "^7.0.0",
"@babel/core": "^7.2.2",
"@babel/node": "^7.2.2",
Expand Down
2 changes: 2 additions & 0 deletions tests/src/Application.njs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import ServerRequestAndResponse from './ServerRequestAndResponse';
import StatefulComponent from './StatefulComponent';
import StaticThis from './StaticThis';
import TwoWayBindings from './TwoWayBindings';
import TypeScript from './TypeScript';
import UnderscoredAttributes from './UnderscoredAttributes';
import Vunerability from './Vunerability';
import WindowDependency from './WindowDependency';
Expand Down Expand Up @@ -92,6 +93,7 @@ class Application extends Nullstack {
<UnderscoredAttributes route="/underscored-attributes" />
<IsomorphicStartup route="/isomorphic-startup" />
<WorkerVerbs route="/worker-verbs" />
<TypeScript route="/typescript" />
<LazyComponentLoader route="/lazy-component" />
<ErrorPage route="*" />
</main>
Expand Down
36 changes: 36 additions & 0 deletions tests/src/TypeScript.nts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Nullstack from 'nullstack';
import { NullstackClientContext } from 'nullstack/types';

interface TypeScriptClientContext extends NullstackClientContext {
value: number
}

class TypeScript extends Nullstack {

count: number = 1;

incrementByCount({ value }: TypeScriptClientContext) {
this.count += value
}

renderInnerComponent() {
return <div data-inner-component />
}

render({ self }: NullstackClientContext) {
return (
<div data-count={this.count}>
<input bind={this.count} />
<button
data-initiated={self.initiated}
value={1}
onclick={this.incrementByCount}
> TS </button>
<InnerComponent />
</div>
)
}

}

export default TypeScript;
43 changes: 43 additions & 0 deletions tests/src/TypesScript.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const puppeteer = require('puppeteer');

let browser;
let page;

beforeAll(async () => {
browser = await puppeteer.launch();
page = await browser.newPage();
await page.goto('http://localhost:6969/typescript');
});

describe('UnderscoredAttributes', () => {

test('context has types', async () => {
await page.waitForSelector('[data-initiated]');
const element = await page.$('[data-initiated]');
expect(element).toBeTruthy();
});

test('context can be extended', async () => {
await page.click('button[value="1"]');
await page.waitForSelector('[data-count="2"]');
const element = await page.$('[data-count="2"]');
expect(element).toBeTruthy();
});

test('inner components work on nts files', async () => {
await page.waitForSelector('[data-inner-component]');
const element = await page.$('[data-inner-component]');
expect(element).toBeTruthy();
});

test('bind should work on nts files', async () => {
await page.waitForSelector('[bind="count"]');
const element = await page.$('[bind="count"]');
expect(element).toBeTruthy();
});

});

afterAll(async () => {
browser.close();
});
106 changes: 106 additions & 0 deletions types/ClientContext.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { NullstackEnvironment } from "./Environment";
import { NullstackPage } from "./Page";
import { NullstackParams } from "./Params";
import { NullstackProject } from "./Project";
import { NullstackRouter } from "./Router";
import { NullstackSelf } from "./Self";
import { NullstackSettings } from "./Settings";
import { NullstackWorker } from "./Worker";

/**
* https://nullstack.app/context
*/
export type NullstackClientContext = {

/**
* Information about the document `head` metatags.
*
* https://nullstack.app/context-page
*/
page?: NullstackPage,

/**
* Information about the app manifest and some metatags.
*
* https://nullstack.app/context-project
*/
project?: NullstackProject,

/**
* Gives you granular control of your PWA behavior.
*
* https://nullstack.app/service-worker
*/
worker?: NullstackWorker,

/**
* It gives you information about the instance lifecycle and it's unique [key](https://nullstack.app/instance-self#instance-key).
*
* https://nullstack.app/instance-self
*/
self?: NullstackSelf,

/**
* It gives you information about the element dataset.
*
* Any `data-*` attributes will receive a respective camelized key on this object.
*
* Only on client.
*
* https://nullstack.app/context-data
*/
data?: object,

/**
* It gives you all active instances of the application.
*
* Adding a [key](https://nullstack.app/instance-self#instance-key) to a Component adds it here.
*
* Only on client.
*
* https://nullstack.app/context-instances
*/
instances?: object,

/**
* It gives you information about the current environment.
*
* https://nullstack.app/context-environment
*/
environment?: NullstackEnvironment,

/**
* Each query string param is mapped to this object.
*
* https://nullstack.app/routes-and-params#params
* @example
* "/?expanded=true&page=2" === {expanded: true, page: 2}
*/
params?: NullstackParams,

/**
* Nullstack router.
*
* https://nullstack.app/routes-and-params#router
*/
router?: NullstackRouter,

/**
* You can assign any key with any type of public information.
*
* .env `NULLSTACK_SETTINGS_PUBLIC_KEY` -> `settings.publicKey`
*
* https://nullstack.app/context-settings
*/
settings?: NullstackSettings,

/**
* Children elements of this component.
*
* https://nullstack.app/renderable-components#components-with-children
*/
children?: any,

[key: string]: any

};
20 changes: 20 additions & 0 deletions types/Environment.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export type NullstackEnvironment = {

client: boolean,

server: boolean,

development: boolean,

production: boolean,

static: boolean,

/**
* md5 hash of the current environment folder outputs.
*
* https://nullstack.app/context-environment
*/
key: string

};
79 changes: 79 additions & 0 deletions types/Page.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
export type NullstackPage = {

/**
* Current page title
*
* https://nullstack.app/context-page
*/
title: string,

/**
* Path to site banner at **public** folder
*
* https://nullstack.app/context-page
*/
image: string,

/**
* Current page description
*
* https://nullstack.app/context-page
*/
description?: string,

/**
* Absolute canonical url
*
* https://nullstack.app/context-page
*/
canonical: string,

/**
* Current page locale, example: `en-US`
*
* https://nullstack.app/context-page
*/
locale: string,

/**
* Related to robots.txt file generation
*
* https://nullstack.app/context-page
*/
robots: string,

schema?: object,

/**
* Represents the `changefreq` key in the **sitemap.xml**
*
* https://nullstack.app/context-page
*/
changes: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never',

/**
* Represents the `priority` key in the **sitemap.xml**
*
* sitemaps assume a `0.5` priority
*
* https://nullstack.app/context-page
*/
priority: number,

/**
* The page current HTTP response, example: `200`
*
* https://nullstack.app/context-page
*/
status: number,

/**
* Event raised when `page.title` changes.
*
* Only on client.
*
* https://nullstack.app/context-page#custom-events
*/
event: string

};
3 changes: 3 additions & 0 deletions types/Params.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type NullstackParams = {
[key: string]: string | boolean
};
Loading