diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index d7256cb..0000000 --- a/.eslintignore +++ /dev/null @@ -1,6 +0,0 @@ -tap-snapshots -node_modules -modules -utils -dist -tmp \ No newline at end of file diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index b53fbca..0000000 --- a/.eslintrc +++ /dev/null @@ -1,16 +0,0 @@ -{ - "env": { - "es6": true, - "node": true, - "browser": false - }, - "parserOptions": { - "ecmaVersion": 2020 - }, - "extends": "airbnb-base", - "rules": { - "indent": [1, 4], - "import/prefer-default-export": [0], - "import/extensions": [0] - } -} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..b21e22b --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,31 @@ +import prettierConfig from "eslint-config-prettier"; +import prettierPlugin from "eslint-plugin-prettier"; +import globals from "globals"; +import js from "@eslint/js"; + +export default [ + js.configs.recommended, + prettierConfig, + { + plugins: { + prettier: prettierPlugin, + }, + languageOptions: { + globals: { + ...globals.node, + ...globals.browser, + global: true, + }, + }, + }, + { + ignores: [ + "tap-snapshots/*", + "node_modules/*", + "modules/*", + "utils/*", + "dist/*", + "tmp/*", + ], + }, +]; diff --git a/fixtures/modules/simple/app/views.js b/fixtures/modules/simple/app/views.js index 2462283..7b354de 100644 --- a/fixtures/modules/simple/app/views.js +++ b/fixtures/modules/simple/app/views.js @@ -1,5 +1,5 @@ -import { html, css } from 'lit-element'; +import { html } from "lit-element"; export default function view(items) { - return html`

Hello ${items[0]}!

`; + return html`

Hello ${items[0]}!

`; } diff --git a/package.json b/package.json index e13b893..13d4e21 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,7 @@ ], "scripts": { "test": "tap --disable-coverage --allow-empty-coverage", - "lint": "eslint . --ext=js", - "lint:fix": "eslint . --fix --ext=js" + "lint": "eslint ." }, "repository": { "type": "git", @@ -37,10 +36,11 @@ "@semantic-release/changelog": "6.0.3", "@semantic-release/git": "10.0.1", "esbuild": "0.22.0", - "eslint": "8.57.0", - "eslint-config-airbnb-base": "15.0.0", - "eslint-plugin-import": "2.29.1", + "eslint": "9.6.0", + "eslint-config-prettier": "9.1.0", + "eslint-plugin-prettier": "5.1.3", "fastify": "4.28.1", + "globals": "15.8.0", "semantic-release": "23.1.1", "tap": "20.0.3" }, diff --git a/src/plugin.js b/src/plugin.js index 7f42875..a4ddf82 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -1,56 +1,51 @@ -/* eslint-disable no-restricted-syntax */ - -import * as importMapPlugin from 'esbuild-plugin-import-map'; -import { helpers } from '@eik/common'; -import { request } from 'undici'; +import * as importMapPlugin from "esbuild-plugin-import-map"; +import { helpers } from "@eik/common"; +import { request } from "undici"; const fetchImportMaps = async (urls = []) => { - try { - const maps = urls.map(async (map) => { - const { - statusCode, - body, - } = await request(map, { maxRedirections: 2 }); - - if (statusCode === 404) { - throw new Error('Import map could not be found on server'); - } else if (statusCode >= 400 && statusCode < 500) { - throw new Error('Server rejected client request'); - } else if (statusCode >= 500) { - throw new Error('Server error'); - } - return body.json(); - }); - return await Promise.all(maps); - } catch (err) { - throw new Error( - `Unable to load import map file from server: ${err.message}`, - ); - } + try { + const maps = urls.map(async (map) => { + const { statusCode, body } = await request(map, { maxRedirections: 2 }); + + if (statusCode === 404) { + throw new Error("Import map could not be found on server"); + } else if (statusCode >= 400 && statusCode < 500) { + throw new Error("Server rejected client request"); + } else if (statusCode >= 500) { + throw new Error("Server error"); + } + return body.json(); + }); + return await Promise.all(maps); + } catch (err) { + throw new Error( + `Unable to load import map file from server: ${err.message}` + ); + } }; export async function load({ - path = process.cwd(), - maps = [], - urls = [], + path = process.cwd(), + maps = [], + urls = [], } = {}) { - const pMaps = Array.isArray(maps) ? maps : [maps]; - const pUrls = Array.isArray(urls) ? urls : [urls]; + const pMaps = Array.isArray(maps) ? maps : [maps]; + const pUrls = Array.isArray(urls) ? urls : [urls]; - const config = await helpers.getDefaults(path); + const config = await helpers.getDefaults(path); - const fetched = await fetchImportMaps([...config.map, ...pUrls]); - const mappings = pMaps.concat(fetched); + const fetched = await fetchImportMaps([...config.map, ...pUrls]); + const mappings = pMaps.concat(fetched); - await importMapPlugin.load(mappings); + await importMapPlugin.load(mappings); } export function clear() { - importMapPlugin.clear(); + importMapPlugin.clear(); } export function plugin() { - const obj = importMapPlugin.plugin(); - obj.name = '@eik/esbuild-plugin'; - return obj; + const obj = importMapPlugin.plugin(); + obj.name = "@eik/esbuild-plugin"; + return obj; } diff --git a/test/plugin.js b/test/plugin.js index 91baf44..5271674 100644 --- a/test/plugin.js +++ b/test/plugin.js @@ -1,13 +1,11 @@ -/* eslint-disable no-restricted-syntax */ +import fastify from "fastify"; +import esbuild from "esbuild"; +import path from "path"; +import tap from "tap"; +import fs from "fs"; -import fastify from 'fastify'; -import esbuild from 'esbuild'; -import path from 'path'; -import tap from 'tap'; -import fs from 'fs'; - -import { __dirname } from '../utils/dirname.js'; -import * as plugin from '../src/plugin.js'; +import { __dirname } from "../utils/dirname.js"; +import * as plugin from "../src/plugin.js"; const file = `${__dirname}/../fixtures/modules/file/main.js`; @@ -15,225 +13,263 @@ const file = `${__dirname}/../fixtures/modules/file/main.js`; * When running tests on Windows, the output code get some extra \r on each line. * Remove these so snapshots work on all OSes. */ -const clean = (str) => str.split('\r').join(''); +const clean = (str) => str.split("\r").join(""); const bufferToString = (buff) => { - const str = []; - for (const out of buff) { - str.push(new TextDecoder('utf-8').decode(out.contents)); - } - return str.join(''); + const str = []; + for (const out of buff) { + str.push(new TextDecoder("utf-8").decode(out.contents)); + } + return str.join(""); }; -tap.test('plugin() - import map fetched from a URL', async (t) => { - const app = fastify(); - app.server.keepAliveTimeout = 20; - app.get('/one', (request, reply) => { - reply.send({ - imports: { - 'lit-element': 'https://cdn.eik.dev/lit-element/v2', - }, - }); +tap.test("plugin() - import map fetched from a URL", async (t) => { + const app = fastify(); + app.server.keepAliveTimeout = 20; + app.get("/one", (request, reply) => { + reply.send({ + imports: { + "lit-element": "https://cdn.eik.dev/lit-element/v2", + }, }); - app.get('/two', (request, reply) => { - reply.send({ - imports: { - 'lit-html': 'https://cdn.eik.dev/lit-html/v1', - }, - }); + }); + app.get("/two", (request, reply) => { + reply.send({ + imports: { + "lit-html": "https://cdn.eik.dev/lit-html/v1", + }, }); - const address = await app.listen(); + }); + const address = await app.listen(); - await fs.promises.writeFile(path.join(process.cwd(), 'eik.json'), JSON.stringify({ - name: 'test', - server: 'https://localhost', - version: '1.0.0', - files: './dist', - 'import-map': `${address}/one`, - })); + await fs.promises.writeFile( + path.join(process.cwd(), "eik.json"), + JSON.stringify({ + name: "test", + server: "https://localhost", + version: "1.0.0", + files: "./dist", + "import-map": `${address}/one`, + }) + ); - await plugin.load({ - maps: [{ - imports: { - 'lit-html/lit-html': 'https://cdn.eik.dev/lit-html/v2', - }, - }], - urls: [`${address}/one`, `${address}/two`], - }); + await plugin.load({ + maps: [ + { + imports: { + "lit-html/lit-html": "https://cdn.eik.dev/lit-html/v2", + }, + }, + ], + urls: [`${address}/one`, `${address}/two`], + }); - const result = await esbuild.build({ - entryPoints: [file], - bundle: true, - format: 'esm', - minify: false, - sourcemap: false, - target: ['esnext'], - plugins: [plugin.plugin()], - write: false, - }); + const result = await esbuild.build({ + entryPoints: [file], + bundle: true, + format: "esm", + minify: false, + sourcemap: false, + target: ["esnext"], + plugins: [plugin.plugin()], + write: false, + }); - const code = bufferToString(result.outputFiles); - t.matchSnapshot(clean(code), 'import maps from urls'); + const code = bufferToString(result.outputFiles); + t.matchSnapshot(clean(code), "import maps from urls"); - plugin.clear(); - await app.close(); - await fs.promises.unlink(path.join(process.cwd(), 'eik.json')); - t.end(); + plugin.clear(); + await app.close(); + await fs.promises.unlink(path.join(process.cwd(), "eik.json")); + t.end(); }); -tap.test('plugin() - import map fetched from a URL via eik.json', async (t) => { - const app = fastify(); - app.server.keepAliveTimeout = 20; - app.get('/one', (request, reply) => { - reply.send({ - imports: { - 'lit-element': 'https://cdn.eik.dev/lit-element/v2', - 'lit-html': 'https://cdn.eik.dev/lit-html/v1', - 'lit-html/lit-html': 'https://cdn.eik.dev/lit-html/v2', - }, - }); +tap.test("plugin() - import map fetched from a URL via eik.json", async (t) => { + const app = fastify(); + app.server.keepAliveTimeout = 20; + app.get("/one", (request, reply) => { + reply.send({ + imports: { + "lit-element": "https://cdn.eik.dev/lit-element/v2", + "lit-html": "https://cdn.eik.dev/lit-html/v1", + "lit-html/lit-html": "https://cdn.eik.dev/lit-html/v2", + }, }); - const address = await app.listen(); + }); + const address = await app.listen(); - await fs.promises.writeFile(path.join(process.cwd(), 'eik.json'), JSON.stringify({ - name: 'test', - server: 'https://localhost', - version: '1.0.0', - files: './dist', - 'import-map': `${address}/one`, - })); + await fs.promises.writeFile( + path.join(process.cwd(), "eik.json"), + JSON.stringify({ + name: "test", + server: "https://localhost", + version: "1.0.0", + files: "./dist", + "import-map": `${address}/one`, + }) + ); - await plugin.load(); + await plugin.load(); - const result = await esbuild.build({ - entryPoints: [file], - bundle: true, - format: 'esm', - minify: false, - sourcemap: false, - target: ['esnext'], - plugins: [plugin.plugin()], - write: false, - }); + const result = await esbuild.build({ + entryPoints: [file], + bundle: true, + format: "esm", + minify: false, + sourcemap: false, + target: ["esnext"], + plugins: [plugin.plugin()], + write: false, + }); - const code = bufferToString(result.outputFiles); - t.matchSnapshot(clean(code), 'eik.json import-map string'); + const code = bufferToString(result.outputFiles); + t.matchSnapshot(clean(code), "eik.json import-map string"); - plugin.clear(); - await app.close(); - await fs.promises.unlink(path.join(process.cwd(), 'eik.json')); - t.end(); + plugin.clear(); + await app.close(); + await fs.promises.unlink(path.join(process.cwd(), "eik.json")); + t.end(); }); -tap.test('plugin() - import maps via eik.json, URLs and direct definitions', async (t) => { +tap.test( + "plugin() - import maps via eik.json, URLs and direct definitions", + async (t) => { const app = fastify(); app.server.keepAliveTimeout = 20; - app.get('/one', (request, reply) => { - reply.send({ - imports: { - 'lit-element': 'https://cdn.eik.dev/lit-element/v2', - }, - }); + app.get("/one", (request, reply) => { + reply.send({ + imports: { + "lit-element": "https://cdn.eik.dev/lit-element/v2", + }, + }); }); - app.get('/two', (request, reply) => { - reply.send({ - imports: { - 'lit-html': 'https://cdn.eik.dev/lit-html/v1', - }, - }); + app.get("/two", (request, reply) => { + reply.send({ + imports: { + "lit-html": "https://cdn.eik.dev/lit-html/v1", + }, + }); }); const address = await app.listen(); - await fs.promises.writeFile(path.join(process.cwd(), 'eik.json'), JSON.stringify({ - name: 'test', - version: '1.0.0', - server: 'https://localhost', - files: './dist', - 'import-map': `${address}/one`, - })); + await fs.promises.writeFile( + path.join(process.cwd(), "eik.json"), + JSON.stringify({ + name: "test", + version: "1.0.0", + server: "https://localhost", + files: "./dist", + "import-map": `${address}/one`, + }) + ); await plugin.load({ - maps: [{ - imports: { - 'lit-html/lit-html': 'https://cdn.eik.dev/lit-html/v2', - }, - }], - urls: [`${address}/two`], + maps: [ + { + imports: { + "lit-html/lit-html": "https://cdn.eik.dev/lit-html/v2", + }, + }, + ], + urls: [`${address}/two`], }); const result = await esbuild.build({ - entryPoints: [file], - bundle: true, - format: 'esm', - minify: false, - sourcemap: false, - target: ['esnext'], - plugins: [plugin.plugin()], - write: false, + entryPoints: [file], + bundle: true, + format: "esm", + minify: false, + sourcemap: false, + target: ["esnext"], + plugins: [plugin.plugin()], + write: false, }); const code = bufferToString(result.outputFiles); - t.matchSnapshot(clean(code), 'import maps from eik.json, urls and direct definition'); + t.matchSnapshot( + clean(code), + "import maps from eik.json, urls and direct definition" + ); plugin.clear(); await app.close(); - await fs.promises.unlink(path.join(process.cwd(), 'eik.json')); + await fs.promises.unlink(path.join(process.cwd(), "eik.json")); t.end(); -}); + } +); -tap.test('plugin() - import maps via package.json, URLs and direct definitions', async (t) => { +tap.test( + "plugin() - import maps via package.json, URLs and direct definitions", + async (t) => { const app = fastify(); app.server.keepAliveTimeout = 20; - app.get('/one', (request, reply) => { - reply.send({ - imports: { - 'lit-element': 'https://cdn.eik.dev/lit-element/v2', - }, - }); + app.get("/one", (request, reply) => { + reply.send({ + imports: { + "lit-element": "https://cdn.eik.dev/lit-element/v2", + }, + }); }); - app.get('/two', (request, reply) => { - reply.send({ - imports: { - 'lit-html': 'https://cdn.eik.dev/lit-html/v1', - }, - }); + app.get("/two", (request, reply) => { + reply.send({ + imports: { + "lit-html": "https://cdn.eik.dev/lit-html/v1", + }, + }); }); const address = await app.listen(); - const packageJSON = JSON.parse(await fs.promises.readFile(path.join(process.cwd(), 'package.json'), 'utf-8')); + const packageJSON = JSON.parse( + await fs.promises.readFile( + path.join(process.cwd(), "package.json"), + "utf-8" + ) + ); packageJSON.eik = { - server: 'https://localhost', - files: './dist', - 'import-map': `${address}/one`, + server: "https://localhost", + files: "./dist", + "import-map": `${address}/one`, }; - await fs.promises.writeFile(path.join(process.cwd(), 'package.json'), `${JSON.stringify(packageJSON, null, 2)}\n`); + await fs.promises.writeFile( + path.join(process.cwd(), "package.json"), + `${JSON.stringify(packageJSON, null, 2)}\n` + ); await plugin.load({ - maps: [{ - imports: { - 'lit-html/lit-html': 'https://cdn.eik.dev/lit-html/v2', - }, - }], - urls: [`${address}/two`], + maps: [ + { + imports: { + "lit-html/lit-html": "https://cdn.eik.dev/lit-html/v2", + }, + }, + ], + urls: [`${address}/two`], }); const result = await esbuild.build({ - entryPoints: [file], - bundle: true, - format: 'esm', - minify: false, - sourcemap: false, - target: ['esnext'], - plugins: [plugin.plugin()], - write: false, + entryPoints: [file], + bundle: true, + format: "esm", + minify: false, + sourcemap: false, + target: ["esnext"], + plugins: [plugin.plugin()], + write: false, }); const code = bufferToString(result.outputFiles); - t.matchSnapshot(clean(code), 'import maps from eik.json, urls and direct definition'); + t.matchSnapshot( + clean(code), + "import maps from eik.json, urls and direct definition" + ); plugin.clear(); await app.close(); delete packageJSON.eik; - await fs.promises.writeFile(path.join(process.cwd(), 'package.json'), `${JSON.stringify(packageJSON, null, 2)}\n`); + await fs.promises.writeFile( + path.join(process.cwd(), "package.json"), + `${JSON.stringify(packageJSON, null, 2)}\n` + ); t.end(); -}); + } +);