diff --git a/example-apps/typescript/.gitignore b/example-apps/typescript/.gitignore index 32dd95d8b..ae6ff4e5e 100644 --- a/example-apps/typescript/.gitignore +++ b/example-apps/typescript/.gitignore @@ -31,6 +31,7 @@ bower_components # Compiled binary addons (https://nodejs.org/api/addons.html) build/ +dist/ # Dependency directories node_modules/ diff --git a/example-apps/typescript/README.md b/example-apps/typescript/README.md index 162f536de..48041dfbf 100644 --- a/example-apps/typescript/README.md +++ b/example-apps/typescript/README.md @@ -22,21 +22,3 @@ zapier push ``` Find out more on the latest docs: https://github.com/zapier/zapier-platform/blob/main/packages/cli/README.md. - -# The "typescript" Template - -This example is mainly a proof-of-concept for using features not yet available -in Node. - -In `package.json`, we've define some commonly-used scripts: - -```bash -# Watch and compile as you edit code -npm run watch - -# There's also a non-watch compile command -npm run build - -# To push to Zapier, make sure you compile first -npm run build && zapier push -``` diff --git a/example-apps/typescript/index.js b/example-apps/typescript/index.js index 4d5e21a46..aaa66797e 100644 --- a/example-apps/typescript/index.js +++ b/example-apps/typescript/index.js @@ -1 +1 @@ -module.exports = require('./lib').default; +module.exports = require('./dist').default; diff --git a/example-apps/typescript/package.json b/example-apps/typescript/package.json index a583975cb..fdc81d34d 100644 --- a/example-apps/typescript/package.json +++ b/example-apps/typescript/package.json @@ -2,24 +2,20 @@ "name": "typescript", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "dist/index.js", "scripts": { - "test": "npm run build && jest --testTimeout 10000 --rootDir ./lib/test", + "test": "vitest", "build": "npm run clean && tsc", - "clean": "rimraf ./lib ./build", - "watch": "npm run clean && tsc --watch", + "clean": "rimraf ./dist ./build", "_zapier-build": "npm run build" }, "dependencies": { "zapier-platform-core": "15.16.1" }, "devDependencies": { - "jest": "^25.5.3", - "@types/jest": "^25.2.1", - "@types/node": "^13.13.5", - "@types/node-fetch": "^2.6.11", - "rimraf": "^3.0.2", - "typescript": "^5.5.3" + "rimraf": "^5.0.10", + "typescript": "^5.5.4", + "vitest": "^2.0.5" }, "private": true } diff --git a/example-apps/typescript/src/creates/movie.ts b/example-apps/typescript/src/creates/movie.ts index efbaffb6c..79b7bec56 100644 --- a/example-apps/typescript/src/creates/movie.ts +++ b/example-apps/typescript/src/creates/movie.ts @@ -1,11 +1,6 @@ -import { Bundle, ZObject } from 'zapier-platform-core'; +import { Create, PerformFunction } from 'zapier-platform-core'; -// You can optionally add add the shape of the inputData in bundle, which will pass that -// info down into the function and tests -const perform = async ( - z: ZObject, - bundle: Bundle<{ title: string; year: number }> -) => { +const perform: PerformFunction = async (z, bundle) => { const response = await z.request({ method: 'POST', url: 'https://auth-json-server.zapier-staging.com/movies', @@ -37,4 +32,4 @@ export default { title: 'example', }, }, -}; +} satisfies Create; diff --git a/example-apps/typescript/src/index.ts b/example-apps/typescript/src/index.ts index ba40ba97f..63c421255 100644 --- a/example-apps/typescript/src/index.ts +++ b/example-apps/typescript/src/index.ts @@ -1,16 +1,12 @@ -import { Bundle, HttpRequestOptions, ZObject } from 'zapier-platform-core'; +import type { App, BeforeRequestMiddleware } from 'zapier-platform-core'; import MovieCreate from './creates/movie'; import MovieTrigger from './triggers/movie'; import { version as platformVersion } from 'zapier-platform-core'; -const { version } = require('../package.json'); +import packageJson from '../package.json'; -const addApiKeyHeader = ( - req: HttpRequestOptions, - z: ZObject, - bundle: Bundle -) => { +const addApiKeyHeader: BeforeRequestMiddleware = (req, z, bundle) => { // Hard-coded api key just to demo. DON'T do auth like this for your production app! req.headers = req.headers || {}; req.headers['X-Api-Key'] = 'secret'; @@ -18,7 +14,7 @@ const addApiKeyHeader = ( }; export default { - version, + version: packageJson.version, platformVersion, beforeRequest: [addApiKeyHeader], @@ -30,4 +26,4 @@ export default { creates: { [MovieCreate.key]: MovieCreate, }, -}; +} satisfies App; diff --git a/example-apps/typescript/src/test/creates.test.ts b/example-apps/typescript/src/test/creates.test.ts index 5a0d6fb19..e133d7d60 100644 --- a/example-apps/typescript/src/test/creates.test.ts +++ b/example-apps/typescript/src/test/creates.test.ts @@ -1,6 +1,5 @@ -/* globals describe, expect, test */ - import { createAppTester, tools } from 'zapier-platform-core'; +import { describe, test, expect } from 'vitest'; import App from '../index'; diff --git a/example-apps/typescript/src/test/triggers.test.ts b/example-apps/typescript/src/test/triggers.test.ts index 147aeafdc..462eaf131 100644 --- a/example-apps/typescript/src/test/triggers.test.ts +++ b/example-apps/typescript/src/test/triggers.test.ts @@ -1,6 +1,5 @@ -/* globals describe, expect, test */ - -import { Bundle, createAppTester, tools } from 'zapier-platform-core'; +import { createAppTester, tools } from 'zapier-platform-core'; +import { describe, test, expect } from 'vitest'; import App from '../index'; diff --git a/example-apps/typescript/src/triggers/movie.ts b/example-apps/typescript/src/triggers/movie.ts index 66eaf4268..eaaa2ad3d 100644 --- a/example-apps/typescript/src/triggers/movie.ts +++ b/example-apps/typescript/src/triggers/movie.ts @@ -1,6 +1,6 @@ -import { Bundle, ZObject } from 'zapier-platform-core'; +import { PerformFunction, Trigger } from 'zapier-platform-core'; -const perform = async (z: ZObject, bundle: Bundle) => { +const perform: PerformFunction = async (z, bundle) => { const response = await z.request( 'https://auth-json-server.zapier-staging.com/movies' ); @@ -17,10 +17,11 @@ export default { }, operation: { + type: 'polling', perform, sample: { id: '1', title: 'example', }, }, -}; +} satisfies Trigger; diff --git a/example-apps/typescript/tsconfig.json b/example-apps/typescript/tsconfig.json index 6460365c8..b984a0df6 100644 --- a/example-apps/typescript/tsconfig.json +++ b/example-apps/typescript/tsconfig.json @@ -1,12 +1,16 @@ { "compilerOptions": { "target": "ESNext", - "module": "commonjs", - "moduleResolution": "node", - "lib": ["esnext"], - "outDir": "./lib", + "module": "CommonJS", + "moduleResolution": "Node", + "resolveJsonModule": true, + "esModuleInterop": true, + "isolatedModules": true, + "skipLibCheck": true, + "outDir": "./dist", "rootDir": "./src", - "strict": true, - "skipLibCheck": true - } + "strict": true + }, + "include": ["./src/**/*.ts"], + "exclude": ["./**/*.test.ts"] } diff --git a/packages/cli/src/generators/index.js b/packages/cli/src/generators/index.js index 3ab1a66b6..4a8dfe9b8 100644 --- a/packages/cli/src/generators/index.js +++ b/packages/cli/src/generators/index.js @@ -56,6 +56,31 @@ const writeGenericPackageJson = (gen, packageJsonExtension) => { ); }; +const writeTypeScriptPackageJson = (gen, packageJsonExtension) => { + gen.fs.writeJSON( + gen.destinationPath('package.json'), + merge( + { + name: gen.options.packageName, + version: '1.0.0', + description: '', + main: 'src/index.js', + scripts: { + test: 'vitest', + }, + dependencies: { + [PLATFORM_PACKAGE]: PACKAGE_VERSION, + }, + devDependencies: { + vitest: '^2.1.2', + }, + private: true, + }, + packageJsonExtension + ) + ); +}; + const writeGenericIndex = (gen, hasAuth) => { gen.fs.copyTpl( gen.templatePath('index.template.js'), @@ -116,7 +141,6 @@ const writeForMinimalTemplate = (gen) => { // example directory const writeForStandaloneTemplate = (gen) => { writeGitignore(gen); - writeGenericReadme(gen); appendReadme(gen); @@ -128,24 +152,38 @@ const writeForStandaloneTemplate = (gen) => { 'form-data': '4.0.0', }, }, + }[gen.options.template]; + + writeGenericPackageJson(gen, packageJsonExtension); + + gen.fs.copy( + gen.templatePath(gen.options.template, '**', '*.{js,json,ts}'), + gen.destinationPath() + ); +}; + +const writeForStandaloneTypeScriptTemplate = (gen) => { + writeGitignore(gen); + writeGenericReadme(gen); + appendReadme(gen); + + const packageJsonExtension = { typescript: { scripts: { + test: 'vitest', + clean: 'rimraf ./dist ./build', build: 'npm run clean && tsc', - clean: 'rimraf ./lib ./build', - watch: 'npm run clean && tsc --watch', - test: 'npm run build && jest --testTimeout 10000 --rootDir ./lib/test', + '_zapier-build': 'npm run build', }, devDependencies: { - '@types/jest': '^26.0.23', - '@types/node': '^14', - '@types/node-fetch': '^2.6.11', - rimraf: '^3.0.2', - typescript: '5.5.3', + rimraf: '^5.0.10', + typescript: '5.6.2', + vitest: '^2.1.2', }, }, }[gen.options.template]; - writeGenericPackageJson(gen, packageJsonExtension); + writeTypeScriptPackageJson(gen, packageJsonExtension); gen.fs.copy( gen.templatePath(gen.options.template, '**', '*.{js,json,ts}'), @@ -165,7 +203,7 @@ const TEMPLATE_ROUTES = { oauth2: writeForAuthTemplate, 'search-or-create': writeForStandaloneTemplate, 'session-auth': writeForAuthTemplate, - typescript: writeForStandaloneTemplate, + typescript: writeForStandaloneTypeScriptTemplate, }; const TEMPLATE_CHOICES = Object.keys(TEMPLATE_ROUTES); diff --git a/packages/cli/src/generators/templates/gitignore b/packages/cli/src/generators/templates/gitignore index 32dd95d8b..ae6ff4e5e 100644 --- a/packages/cli/src/generators/templates/gitignore +++ b/packages/cli/src/generators/templates/gitignore @@ -31,6 +31,7 @@ bower_components # Compiled binary addons (https://nodejs.org/api/addons.html) build/ +dist/ # Dependency directories node_modules/ diff --git a/packages/cli/src/generators/templates/typescript/README.md b/packages/cli/src/generators/templates/typescript/README.md index d28ea3e1b..50404c9c9 100644 --- a/packages/cli/src/generators/templates/typescript/README.md +++ b/packages/cli/src/generators/templates/typescript/README.md @@ -1,17 +1,3 @@ -# The "typescript" Template +# TypeScript Template -This example is mainly a proof-of-concept for using features not yet available -in Node. - -In `package.json`, we've define some commonly-used scripts: - -```bash -# Watch and compile as you edit code -npm run watch - -# There's also a non-watch compile command -npm run build - -# To push to Zapier, make sure you compile first -npm run build && zapier push -``` +An TypeScript template for Zapier Integrations. diff --git a/packages/cli/src/generators/templates/typescript/index.js b/packages/cli/src/generators/templates/typescript/index.js index 4d5e21a46..aaa66797e 100644 --- a/packages/cli/src/generators/templates/typescript/index.js +++ b/packages/cli/src/generators/templates/typescript/index.js @@ -1 +1 @@ -module.exports = require('./lib').default; +module.exports = require('./dist').default; diff --git a/packages/cli/src/generators/templates/typescript/src/creates/movie.ts b/packages/cli/src/generators/templates/typescript/src/creates/movie.ts index efbaffb6c..79b7bec56 100644 --- a/packages/cli/src/generators/templates/typescript/src/creates/movie.ts +++ b/packages/cli/src/generators/templates/typescript/src/creates/movie.ts @@ -1,11 +1,6 @@ -import { Bundle, ZObject } from 'zapier-platform-core'; +import { Create, PerformFunction } from 'zapier-platform-core'; -// You can optionally add add the shape of the inputData in bundle, which will pass that -// info down into the function and tests -const perform = async ( - z: ZObject, - bundle: Bundle<{ title: string; year: number }> -) => { +const perform: PerformFunction = async (z, bundle) => { const response = await z.request({ method: 'POST', url: 'https://auth-json-server.zapier-staging.com/movies', @@ -37,4 +32,4 @@ export default { title: 'example', }, }, -}; +} satisfies Create; diff --git a/packages/cli/src/generators/templates/typescript/src/index.ts b/packages/cli/src/generators/templates/typescript/src/index.ts index ba40ba97f..63c421255 100644 --- a/packages/cli/src/generators/templates/typescript/src/index.ts +++ b/packages/cli/src/generators/templates/typescript/src/index.ts @@ -1,16 +1,12 @@ -import { Bundle, HttpRequestOptions, ZObject } from 'zapier-platform-core'; +import type { App, BeforeRequestMiddleware } from 'zapier-platform-core'; import MovieCreate from './creates/movie'; import MovieTrigger from './triggers/movie'; import { version as platformVersion } from 'zapier-platform-core'; -const { version } = require('../package.json'); +import packageJson from '../package.json'; -const addApiKeyHeader = ( - req: HttpRequestOptions, - z: ZObject, - bundle: Bundle -) => { +const addApiKeyHeader: BeforeRequestMiddleware = (req, z, bundle) => { // Hard-coded api key just to demo. DON'T do auth like this for your production app! req.headers = req.headers || {}; req.headers['X-Api-Key'] = 'secret'; @@ -18,7 +14,7 @@ const addApiKeyHeader = ( }; export default { - version, + version: packageJson.version, platformVersion, beforeRequest: [addApiKeyHeader], @@ -30,4 +26,4 @@ export default { creates: { [MovieCreate.key]: MovieCreate, }, -}; +} satisfies App; diff --git a/packages/cli/src/generators/templates/typescript/src/test/creates.test.ts b/packages/cli/src/generators/templates/typescript/src/test/creates.test.ts index 5a0d6fb19..e133d7d60 100644 --- a/packages/cli/src/generators/templates/typescript/src/test/creates.test.ts +++ b/packages/cli/src/generators/templates/typescript/src/test/creates.test.ts @@ -1,6 +1,5 @@ -/* globals describe, expect, test */ - import { createAppTester, tools } from 'zapier-platform-core'; +import { describe, test, expect } from 'vitest'; import App from '../index'; diff --git a/packages/cli/src/generators/templates/typescript/src/test/triggers.test.ts b/packages/cli/src/generators/templates/typescript/src/test/triggers.test.ts index 147aeafdc..462eaf131 100644 --- a/packages/cli/src/generators/templates/typescript/src/test/triggers.test.ts +++ b/packages/cli/src/generators/templates/typescript/src/test/triggers.test.ts @@ -1,6 +1,5 @@ -/* globals describe, expect, test */ - -import { Bundle, createAppTester, tools } from 'zapier-platform-core'; +import { createAppTester, tools } from 'zapier-platform-core'; +import { describe, test, expect } from 'vitest'; import App from '../index'; diff --git a/packages/cli/src/generators/templates/typescript/src/triggers/movie.ts b/packages/cli/src/generators/templates/typescript/src/triggers/movie.ts index 66eaf4268..eaaa2ad3d 100644 --- a/packages/cli/src/generators/templates/typescript/src/triggers/movie.ts +++ b/packages/cli/src/generators/templates/typescript/src/triggers/movie.ts @@ -1,6 +1,6 @@ -import { Bundle, ZObject } from 'zapier-platform-core'; +import { PerformFunction, Trigger } from 'zapier-platform-core'; -const perform = async (z: ZObject, bundle: Bundle) => { +const perform: PerformFunction = async (z, bundle) => { const response = await z.request( 'https://auth-json-server.zapier-staging.com/movies' ); @@ -17,10 +17,11 @@ export default { }, operation: { + type: 'polling', perform, sample: { id: '1', title: 'example', }, }, -}; +} satisfies Trigger; diff --git a/packages/cli/src/generators/templates/typescript/tsconfig.json b/packages/cli/src/generators/templates/typescript/tsconfig.json index db63256e8..b984a0df6 100644 --- a/packages/cli/src/generators/templates/typescript/tsconfig.json +++ b/packages/cli/src/generators/templates/typescript/tsconfig.json @@ -1,11 +1,16 @@ { "compilerOptions": { - "target": "es2019", - "module": "commonjs", - "moduleResolution": "node", - "lib": ["esnext"], - "outDir": "./lib", + "target": "ESNext", + "module": "CommonJS", + "moduleResolution": "Node", + "resolveJsonModule": true, + "esModuleInterop": true, + "isolatedModules": true, + "skipLibCheck": true, + "outDir": "./dist", "rootDir": "./src", "strict": true - } + }, + "include": ["./src/**/*.ts"], + "exclude": ["./**/*.test.ts"] } diff --git a/packages/cli/src/tests/utils/build.js b/packages/cli/src/tests/utils/build.js index 86c104500..4137f45ac 100644 --- a/packages/cli/src/tests/utils/build.js +++ b/packages/cli/src/tests/utils/build.js @@ -51,8 +51,8 @@ describe('build (runs slowly)', function () { // check that only the required lodash files are grabbed smartPaths.should.containEql('index.js'); - smartPaths.should.containEql('lib/index.js'); - smartPaths.should.containEql('lib/triggers/movie.js'); + smartPaths.should.containEql('dist/index.js'); + smartPaths.should.containEql('dist/triggers/movie.js'); smartPaths.filter((p) => p.endsWith('.ts')).length.should.equal(0); smartPaths.should.not.containEql('tsconfig.json'); @@ -64,14 +64,14 @@ describe('build (runs slowly)', function () { return build.listFiles(tmpDir).then((dumbPaths) => { // check that way more than the required package files are grabbed dumbPaths.should.containEql('index.js'); - dumbPaths.should.containEql('lib/index.js'); - dumbPaths.should.containEql('lib/triggers/movie.js'); + dumbPaths.should.containEql('dist/index.js'); + dumbPaths.should.containEql('dist/triggers/movie.js'); dumbPaths.should.containEql('src/index.ts'); dumbPaths.should.containEql('src/triggers/movie.ts'); dumbPaths.should.containEql('tsconfig.json'); - dumbPaths.length.should.be.within(5000, 15000); + dumbPaths.length.should.be.within(3000, 10000); }); }); @@ -307,7 +307,7 @@ describe('build (runs slowly)', function () { await build.maybeRunBuildScript({ cwd: tmpDir }); - const buildExists = await fs.pathExists(path.join(tmpDir, 'lib')); + const buildExists = await fs.pathExists(path.join(tmpDir, 'dist')); should.equal(buildExists, true); }); });