From ccfcc0b88ee6f19b69d3e1cfe14fcac2a846e22b Mon Sep 17 00:00:00 2001 From: esthedebeste <57283066+esthedebeste@users.noreply.github.com> Date: Tue, 16 May 2023 15:33:24 +0200 Subject: [PATCH] feat: add civet processor and transformer --- package.json | 2 + pnpm-lock.yaml | 24 ++++++++ src/index.ts | 1 + src/modules/language.ts | 1 + src/processors/civet.ts | 32 +++++++++++ src/transformers/civet.ts | 38 ++++++++++++ src/types/index.ts | 5 +- test/fixtures/CivetImports.svelte | 5 ++ test/fixtures/script.civet | 1 + test/processors/civet.test.ts | 53 +++++++++++++++++ test/transformers/civet.test.ts | 96 +++++++++++++++++++++++++++++++ 11 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 src/processors/civet.ts create mode 100644 src/transformers/civet.ts create mode 100644 test/fixtures/CivetImports.svelte create mode 100644 test/fixtures/script.civet create mode 100644 test/processors/civet.test.ts create mode 100644 test/transformers/civet.test.ts diff --git a/package.json b/package.json index d9ff15da..a5aab359 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "@babel/preset-env": "^7.20.2", "@commitlint/cli": "^11.0.0", "@commitlint/config-conventional": "^11.0.0", + "@danielx/civet": "^0.6.2", "@kiwi/eslint-config": "^2.0.2", "@kiwi/prettier-config": "^2.0.2", "@types/babel__core": "^7.1.20", @@ -96,6 +97,7 @@ }, "peerDependencies": { "@babel/core": "^7.10.2", + "@danielx/civet": "^0.6.2", "coffeescript": "^2.5.1", "less": "^3.11.3 || ^4.0.0", "postcss": "^7 || ^8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aad57d58..76012e3c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,7 @@ specifiers: '@babel/preset-env': ^7.20.2 '@commitlint/cli': ^11.0.0 '@commitlint/config-conventional': ^11.0.0 + '@danielx/civet': ^0.6.2 '@kiwi/eslint-config': ^2.0.2 '@kiwi/prettier-config': ^2.0.2 '@types/babel__core': ^7.1.20 @@ -49,6 +50,7 @@ devDependencies: '@babel/preset-env': 7.20.2_@babel+core@7.20.5 '@commitlint/cli': 11.0.0 '@commitlint/config-conventional': 11.0.0 + '@danielx/civet': 0.6.2 '@kiwi/eslint-config': 2.0.2_xtpwnnbpkmoalk4brnptc6esbm '@kiwi/prettier-config': 2.0.2_prettier@2.8.1 '@types/babel__core': 7.1.20 @@ -1410,6 +1412,21 @@ packages: engines: {node: '>=v10.22.0'} dev: true + /@cspotcode/source-map-support/0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: true + + /@danielx/civet/0.6.2: + resolution: {integrity: sha512-wApJwBdxRJUgnL/6yDKjIRfOYiVfE2NDP9iWTophrywnMx26Vpm7X3wMtnSUSL8jCgtWTGsvBRrfaRelkv3v8w==} + engines: {node: '>=19 || ^18.6.0 || ^16.17.0'} + hasBin: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + dev: true + /@eslint/eslintrc/1.3.3: resolution: {integrity: sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1718,6 +1735,13 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true + /@jridgewell/trace-mapping/0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: true + /@kiwi/eslint-config/2.0.2_xtpwnnbpkmoalk4brnptc6esbm: resolution: {integrity: sha512-MVH1R5nI4GFoN6/pEl6Pz+WYE+71V8ENX6MtC51/8O9eKq+hX1yJvBXXR55FVvv37F/cmV7KpoE8ebGzAgx/QQ==} peerDependencies: diff --git a/src/index.ts b/src/index.ts index baa7f302..10ee9f81 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,5 +15,6 @@ export { default as scss, default as sass } from './processors/scss'; export { default as stylus } from './processors/stylus'; export { default as postcss } from './processors/postcss'; export { default as globalStyle } from './processors/globalStyle'; +export { default as civet } from './processors/civet'; export { default as babel } from './processors/babel'; export { default as replace } from './processors/replace'; diff --git a/src/modules/language.ts b/src/modules/language.ts index 67481f8b..611ec1df 100644 --- a/src/modules/language.ts +++ b/src/modules/language.ts @@ -41,6 +41,7 @@ export const ALIAS_MAP = new Map([ export const SOURCE_MAP_PROP_MAP: Record = { babel: [['sourceMaps'], true], typescript: [['compilerOptions', 'sourceMap'], true], + civet: [['compilerOptions', 'sourceMap'], true], scss: [['sourceMap'], true], less: [['sourceMap'], {}], stylus: [['sourcemap'], true], diff --git a/src/processors/civet.ts b/src/processors/civet.ts new file mode 100644 index 00000000..a98414f9 --- /dev/null +++ b/src/processors/civet.ts @@ -0,0 +1,32 @@ +import { prepareContent } from '../modules/prepareContent'; +import { getTagInfo } from '../modules/tagInfo'; +import { concat } from '../modules/utils'; + +import type { Options, PreprocessorGroup } from '../types'; + +export default (options?: Options.Typescript): PreprocessorGroup => ({ + async script(svelteFile) { + const { transformer } = await import('../transformers/civet'); + let { content, markup, filename, attributes, lang, dependencies } = + await getTagInfo(svelteFile); + + if (lang !== 'civet') { + return { code: content }; + } + + content = prepareContent({ options, content }); + + const transformed = await transformer({ + content, + markup, + filename, + attributes, + options, + }); + + return { + ...transformed, + dependencies: concat(dependencies, transformed.dependencies), + }; + }, +}); diff --git a/src/transformers/civet.ts b/src/transformers/civet.ts new file mode 100644 index 00000000..0295899f --- /dev/null +++ b/src/transformers/civet.ts @@ -0,0 +1,38 @@ +import { isAbsolute, resolve } from 'path'; + +import { compile } from '@danielx/civet'; + +import { transformer as tsTransform } from './typescript'; + +import type { Options, Transformer } from '../types'; + +const transformer: Transformer = async ({ + content, + filename, + markup, + options = {}, + attributes, +}) => { + const basePath = process.cwd(); + + if (filename == null) return { code: content }; + + filename = isAbsolute(filename) ? filename : resolve(basePath, filename); + + const { code, sourceMap } = compile(content, { + filename, + js: false, + sourceMap: true, + }); + + return tsTransform({ + content: code, + attributes, + filename, + map: sourceMap.json(filename, filename) as object, + markup, + options, + }); +}; + +export { transformer }; diff --git a/src/types/index.ts b/src/types/index.ts index d7b19a68..ababbbaf 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,9 +1,9 @@ import * as Options from './options'; import type { - Processed as SvelteProcessed, - Preprocessor as SveltePreprocessor, PreprocessorGroup, + Preprocessor as SveltePreprocessor, + Processed as SvelteProcessed, } from 'svelte/types/compiler/preprocess'; export { Options }; @@ -74,6 +74,7 @@ export type AutoPreprocessOptions = { // transformers babel?: TransformerOptions; typescript?: TransformerOptions; + civet?: TransformerOptions; scss?: TransformerOptions; sass?: TransformerOptions; less?: TransformerOptions; diff --git a/test/fixtures/CivetImports.svelte b/test/fixtures/CivetImports.svelte new file mode 100644 index 00000000..b711d6a9 --- /dev/null +++ b/test/fixtures/CivetImports.svelte @@ -0,0 +1,5 @@ + + +{hello} \ No newline at end of file diff --git a/test/fixtures/script.civet b/test/fixtures/script.civet new file mode 100644 index 00000000..1ad5febf --- /dev/null +++ b/test/fixtures/script.civet @@ -0,0 +1 @@ +export var hello = 'world' \ No newline at end of file diff --git a/test/processors/civet.test.ts b/test/processors/civet.test.ts new file mode 100644 index 00000000..cd8ffd77 --- /dev/null +++ b/test/processors/civet.test.ts @@ -0,0 +1,53 @@ +import { civet } from '../../src'; +import { getFixtureContent, preprocess } from '../utils'; + +const EXPECTED_SCRIPT = getFixtureContent('script.js'); + +describe(`processor - civet`, () => { + it('should ignore other languages', async () => { + const template = ``; + const options = {}; + + const preprocessed = await preprocess(template, [civet(options)]); + + expect(preprocessed.toString?.()).toBe(template); + }); + + it('should leave other languages untouched', async () => { + const template = ``; + const options = { + stripIndent: true, + prependData: '/* potato */', + }; + + const preprocessed = await preprocess(template, [civet(options)]); + + expect(preprocessed.toString?.()).toBe(template); + }); + + it('should support external src files', async () => { + const template = ``; + const options = { + tsconfigFile: false, + compilerOptions: { module: 'es2015' }, + prependData: '// potato', + }; + + const preprocessed = await preprocess(template, [civet(options)]); + + expect(preprocessed.toString?.()).toContain(EXPECTED_SCRIPT); + }); + + it('should support prepended data', async () => { + const template = ``; + const options = { + tsconfigFile: false, + compilerOptions: { module: 'es2015' }, + prependData: '### potato ###', + }; + + const preprocessed = await preprocess(template, [civet(options)]); + + expect(preprocessed.toString?.()).toContain('/* potato */'); + }); +}); diff --git a/test/transformers/civet.test.ts b/test/transformers/civet.test.ts new file mode 100644 index 00000000..0c4aec65 --- /dev/null +++ b/test/transformers/civet.test.ts @@ -0,0 +1,96 @@ +import sveltePreprocess from '../../src'; +import { getFixtureContent, preprocess, spyConsole } from '../utils'; + +spyConsole({ silent: true }); + +const EXPECTED_SCRIPT = getFixtureContent('script.js'); + +describe('transformer - civet', () => { + const template = `
`; + + describe('configuration file', () => { + it('should work with no compilerOptions', async () => { + const opts = sveltePreprocess({ civet: { tsconfigFile: false } }); + const preprocessed = await preprocess(template, opts); + + expect(preprocessed.toString?.()).toContain('export var hello'); + }); + + it('should work with tsconfigDirectory', async () => { + const opts = sveltePreprocess({ + civet: { + tsconfigFile: false, + tsconfigDirectory: './test/fixtures', + }, + }); + + const preprocessed = await preprocess(template, opts); + + expect(preprocessed.toString?.()).toContain(EXPECTED_SCRIPT); + }); + + it('should work with tsconfigFile', async () => { + const opts = sveltePreprocess({ + civet: { + tsconfigFile: './test/fixtures/tsconfig.json', + }, + }); + + const preprocessed = await preprocess(template, opts); + + expect(preprocessed.toString?.()).toContain(EXPECTED_SCRIPT); + }); + + it('should report config semantic errors in tsconfig file', () => { + const opts = sveltePreprocess({ + civet: { + tsconfigFile: './test/fixtures/tsconfig.semantic.json', + }, + }); + + return expect(preprocess(template, opts)).rejects.toThrow('TS6046'); + }); + + it('should transpile ts to js', async () => { + const opts = sveltePreprocess({ + civet: { + compilerOptions: { + module: 'es6', + sourceMap: false, + }, + }, + }); + + const { code } = await preprocess(template, opts); + + expect(code).toContain(getFixtureContent('script.js')); + }); + + it('should strip unused and type imports', async () => { + const tpl = getFixtureContent('CivetImports.svelte'); + + const opts = sveltePreprocess({ + civet: { tsconfigFile: false }, + }); + + const { code } = await preprocess(tpl, opts); + + expect(code).toContain(`import { hello } from "./script.civet"`); + }); + + it('should produce sourcemap', async () => { + const tpl = getFixtureContent('CivetImports.svelte'); + + const opts = sveltePreprocess({ + civet: { tsconfigFile: false }, + sourceMap: true, + }); + + const { map } = await preprocess(tpl, opts); + + expect(map).toHaveProperty('sources', ['App.svelte']); + }); + }); +});