From 97a5b9ab0b151363c44783fb673805a0d69d464a Mon Sep 17 00:00:00 2001 From: Dan Imhoff Date: Thu, 16 Jul 2020 11:39:53 -0700 Subject: [PATCH] chore(cli): update plugin generation and plugin template (#3241) Co-authored-by: Ian Keith --- cli/src/tasks/new-plugin.ts | 102 ++++++++++-------- plugin-template/.prettierignore | 2 + plugin-template/android/Plugin.java | 4 +- .../android/ExampleInstrumentedTest.java | 9 +- .../com/getcapacitor/ExampleUnitTest.java | 7 +- plugin-template/ios/Plugin/Plugin.swift | 2 +- .../ios/PluginTests/PluginTests.swift | 16 +-- plugin-template/ios/Podfile | 2 +- plugin-template/rollup.config.js | 19 ++-- plugin-template/src/definitions.ts | 4 +- plugin-template/src/index.ts | 2 +- plugin-template/src/web.ts | 4 +- plugin-template/tsconfig.json | 8 +- 13 files changed, 103 insertions(+), 78 deletions(-) create mode 100644 plugin-template/.prettierignore diff --git a/cli/src/tasks/new-plugin.ts b/cli/src/tasks/new-plugin.ts index 6f9a22e4c..33ee31716 100644 --- a/cli/src/tasks/new-plugin.ts +++ b/cli/src/tasks/new-plugin.ts @@ -46,19 +46,19 @@ export async function newPlugin(config: Config) { { type: 'input', name: 'name', - message: 'Plugin NPM name (kebab-case):', + message: 'Plugin npm name (kebab-case. ex: capacitor-plugin-example):', validate: requiredInput }, { type: 'input', name: 'domain', - message: 'Plugin id (domain-style syntax. ex: com.example.plugin)', + message: 'Plugin id (domain-style syntax. ex: com.mycompany.plugins.example)', validate: requiredInput }, { type: 'input', name: 'className', - message: 'Plugin class name (ex: AwesomePlugin)', + message: 'Plugin class name (ex: Example)', validate: requiredInput }, { @@ -167,24 +167,24 @@ async function createIosPlugin(config: Config, pluginPath: string, domain: strin } function generatePodspec(config: Config, answers: NewPluginAnswers) { - return ` - require 'json' - - package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) - - Pod::Spec.new do |s| - s.name = '${fixName(answers.name)}' - s.version = package['version'] - s.summary = package['description'] - s.license = package['license'] - s.homepage = package['repository']['url'] - s.author = package['author'] - s.source = { :git => package['repository']['url'], :tag => s.version.to_s } - s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' - s.ios.deployment_target = '${config.ios.minVersion}' - s.dependency 'Capacitor' - s.swift_version = '5.0' - end`; + return `require 'json' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +Pod::Spec.new do |s| + s.name = '${fixName(answers.name)}' + s.version = package['version'] + s.summary = package['description'] + s.license = package['license'] + s.homepage = package['repository']['url'] + s.author = package['author'] + s.source = { :git => package['repository']['url'], :tag => s.version.to_s } + s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' + s.ios.deployment_target = '${config.ios.minVersion}' + s.dependency 'Capacitor' + s.swift_version = '5.1' +end +`; } async function createAndroidPlugin(config: Config, pluginPath: string, domain: string, className: string) { @@ -221,47 +221,61 @@ function generateAndroidManifest(domain: string, pluginPath: string) { function generatePackageJSON(answers: NewPluginAnswers, cliVersion: string) { return { - name: answers.name, - version: '0.0.1', - description: answers.description, - main: 'dist/esm/index.js', - types: 'dist/esm/index.d.ts', - scripts: { - 'build': 'npm run clean && tsc', + 'name': answers.name, + 'version': '0.0.1', + 'description': answers.description, + 'main': 'dist/plugin.js', + 'module': 'dist/esm/index.js', + 'types': 'dist/esm/index.d.ts', + 'scripts': { + 'lint': 'npm run prettier -- --check && npm run swiftlint -- lint', + 'prettier': 'prettier "**/*.{css,html,ts,js,java}"', + 'swiftlint': 'node-swiftlint', + 'build': 'npm run clean && tsc && rollup -c rollup.config.js', 'clean': 'rimraf ./dist', 'watch': 'tsc --watch', 'prepublishOnly': 'npm run build' }, - author: answers.author, - license: answers.license, - dependencies: { - '@capacitor/core': `^${cliVersion}` - }, - devDependencies: { - 'rimraf': '^3.0.0', - 'typescript': '^3.2.4', + 'author': answers.author, + 'license': answers.license, + 'devDependencies': { + '@capacitor/android': `^${cliVersion}`, + '@capacitor/core': `^${cliVersion}`, '@capacitor/ios': `^${cliVersion}`, - '@capacitor/android': `^${cliVersion}` + '@ionic/prettier-config': '^1.0.0', + '@ionic/swiftlint-config': '^1.0.0', + '@rollup/plugin-node-resolve': '^8.1.0', + 'prettier': '^2.0.5', + 'prettier-plugin-java': '^0.8.0', + 'rimraf': '^3.0.0', + 'rollup': '^2.21.0', + 'swiftlint': '^1.0.1', + 'typescript': '~3.8.3' + }, + 'peerDependencies': { + '@capacitor/core': `^${cliVersion}` }, - files: [ + 'files': [ 'dist/', 'ios/', 'android/', `${fixName(answers.name)}.podspec` ], - keywords: [ + 'keywords': [ 'capacitor', 'plugin', 'native' ], - capacitor: { - ios: { - src: 'ios', + 'capacitor': { + 'ios': { + 'src': 'ios', }, - android: { - src: 'android' + 'android': { + 'src': 'android' } }, + 'prettier': '@ionic/prettier-config', + 'swiftlint': '@ionic/swiftlint-config', 'repository': { 'type': 'git', 'url': answers.git diff --git a/plugin-template/.prettierignore b/plugin-template/.prettierignore new file mode 100644 index 000000000..9d0b71a3c --- /dev/null +++ b/plugin-template/.prettierignore @@ -0,0 +1,2 @@ +build +dist diff --git a/plugin-template/android/Plugin.java b/plugin-template/android/Plugin.java index e8c98124c..e0f47c482 100644 --- a/plugin-template/android/Plugin.java +++ b/plugin-template/android/Plugin.java @@ -6,10 +6,10 @@ import com.getcapacitor.PluginCall; import com.getcapacitor.PluginMethod; -@NativePlugin() +@NativePlugin public class CLASS_NAME extends Plugin { - @PluginMethod() + @PluginMethod public void echo(PluginCall call) { String value = call.getString("value"); diff --git a/plugin-template/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java b/plugin-template/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java index 64f83739d..58020e16c 100644 --- a/plugin-template/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java +++ b/plugin-template/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java @@ -1,15 +1,13 @@ package com.getcapacitor.android; -import android.content.Context; +import static org.junit.Assert.*; -import androidx.test.platform.app.InstrumentationRegistry; +import android.content.Context; import androidx.test.ext.junit.runners.AndroidJUnit4; - +import androidx.test.platform.app.InstrumentationRegistry; import org.junit.Test; import org.junit.runner.RunWith; -import static org.junit.Assert.*; - /** * Instrumented test, which will execute on an Android device. * @@ -17,6 +15,7 @@ */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { + @Test public void useAppContext() throws Exception { // Context of the app under test. diff --git a/plugin-template/android/src/test/java/com/getcapacitor/ExampleUnitTest.java b/plugin-template/android/src/test/java/com/getcapacitor/ExampleUnitTest.java index 06806a775..a0fed0cfb 100644 --- a/plugin-template/android/src/test/java/com/getcapacitor/ExampleUnitTest.java +++ b/plugin-template/android/src/test/java/com/getcapacitor/ExampleUnitTest.java @@ -1,17 +1,18 @@ package com.getcapacitor; -import org.junit.Test; - import static org.junit.Assert.*; +import org.junit.Test; + /** * Example local unit test, which will execute on the development machine (host). * * @see Testing documentation */ public class ExampleUnitTest { + @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } -} \ No newline at end of file +} diff --git a/plugin-template/ios/Plugin/Plugin.swift b/plugin-template/ios/Plugin/Plugin.swift index 287b53601..f76f3994c 100644 --- a/plugin-template/ios/Plugin/Plugin.swift +++ b/plugin-template/ios/Plugin/Plugin.swift @@ -7,7 +7,7 @@ import Capacitor */ @objc(CLASS_NAME) public class CLASS_NAME: CAPPlugin { - + @objc func echo(_ call: CAPPluginCall) { let value = call.getString("value") ?? "" call.success([ diff --git a/plugin-template/ios/PluginTests/PluginTests.swift b/plugin-template/ios/PluginTests/PluginTests.swift index 00f036e4c..4e0259932 100644 --- a/plugin-template/ios/PluginTests/PluginTests.swift +++ b/plugin-template/ios/PluginTests/PluginTests.swift @@ -3,33 +3,33 @@ import Capacitor @testable import Plugin class PluginTests: XCTestCase { - + override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } - + func testEcho() { // This is an example of a functional test case for a plugin. // Use XCTAssert and related functions to verify your tests produce the correct results. - + let value = "Hello, World!" let plugin = MyPlugin() - + let call = CAPPluginCall(callbackId: "test", options: [ "value": value - ], success: { (result, call) in + ], success: { (result, _) in let resultValue = result!.data["value"] as? String XCTAssertEqual(value, resultValue) - }, error: { (err) in + }, error: { (_) in XCTFail("Error shouldn't have been called") }) - + plugin.echo(call!) } } diff --git a/plugin-template/ios/Podfile b/plugin-template/ios/Podfile index 8f4ebba29..350751435 100644 --- a/plugin-template/ios/Podfile +++ b/plugin-template/ios/Podfile @@ -13,4 +13,4 @@ end target 'PluginTests' do capacitor_pods -end \ No newline at end of file +end diff --git a/plugin-template/rollup.config.js b/plugin-template/rollup.config.js index 906e8a15e..6994412fb 100644 --- a/plugin-template/rollup.config.js +++ b/plugin-template/rollup.config.js @@ -1,14 +1,21 @@ -import nodeResolve from 'rollup-plugin-node-resolve'; +import nodeResolve from '@rollup/plugin-node-resolve'; export default { input: 'dist/esm/index.js', output: { file: 'dist/plugin.js', format: 'iife', - name: 'capacitorPlugin', - sourcemap: true + name: 'capacitorPlugin', // TODO: change this + globals: { + '@capacitor/core': 'capacitorExports', + }, + sourcemap: true, }, plugins: [ - nodeResolve() - ] -}; \ No newline at end of file + nodeResolve({ + // allowlist of dependencies to bundle in + // @see https://github.com/rollup/plugins/tree/master/packages/node-resolve#resolveonly + resolveOnly: ['lodash'], + }), + ], +}; diff --git a/plugin-template/src/definitions.ts b/plugin-template/src/definitions.ts index 21baf1ba5..23d624e94 100644 --- a/plugin-template/src/definitions.ts +++ b/plugin-template/src/definitions.ts @@ -1,9 +1,9 @@ -declare module "@capacitor/core" { +declare module '@capacitor/core' { interface PluginRegistry { Echo: EchoPlugin; } } export interface EchoPlugin { - echo(options: { value: string }): Promise<{value: string}>; + echo(options: { value: string }): Promise<{ value: string }>; } diff --git a/plugin-template/src/index.ts b/plugin-template/src/index.ts index 6181377f0..5c5939590 100644 --- a/plugin-template/src/index.ts +++ b/plugin-template/src/index.ts @@ -1,2 +1,2 @@ export * from './definitions'; -export * from './web'; \ No newline at end of file +export * from './web'; diff --git a/plugin-template/src/web.ts b/plugin-template/src/web.ts index 9e73d7059..d3bccb308 100644 --- a/plugin-template/src/web.ts +++ b/plugin-template/src/web.ts @@ -5,11 +5,11 @@ export class MyPluginWeb extends WebPlugin implements MyPluginPlugin { constructor() { super({ name: 'MyPlugin', - platforms: ['web'] + platforms: ['web'], }); } - async echo(options: { value: string }): Promise<{value: string}> { + async echo(options: { value: string }): Promise<{ value: string }> { console.log('ECHO', options); return options; } diff --git a/plugin-template/tsconfig.json b/plugin-template/tsconfig.json index 4377384b4..9f458f6e8 100644 --- a/plugin-template/tsconfig.json +++ b/plugin-template/tsconfig.json @@ -1,19 +1,21 @@ { "compilerOptions": { - "allowSyntheticDefaultImports": true, + "allowUnreachableCode": false, "declaration": true, - "experimentalDecorators": true, + "esModuleInterop": true, "lib": [ "dom", "es2015" ], "module": "es2015", "moduleResolution": "node", - "noImplicitAny": true, + "noFallthroughCasesInSwitch": true, "noUnusedLocals": true, "noUnusedParameters": true, "outDir": "dist/esm", + "pretty": true, "sourceMap": true, + "strict": true, "target": "es2015" }, "files": [