svelte-preprocess
Advanced tools
Comparing version 2.9.0 to 2.10.0
@@ -10,2 +10,14 @@ # Changelog | ||
## [v2.10.0](https://github.com/kaisermann/svelte-preprocess/compare/v2.9.0...v2.10.0) - 2019-05-27 | ||
### Merged | ||
- feat: 🎸 add support for typescript type checking [`#37`](https://github.com/kaisermann/svelte-preprocess/pull/37) | ||
### Commits | ||
- refactor: 💡 rename rollup example to svelte-rollup [`5fe4733`](https://github.com/kaisermann/svelte-preprocess/commit/5fe47333e15bfba93989da72ba2a27c847e5aaf8) | ||
- test: 💍 add test for transforming only whats between <template> [`3a045bd`](https://github.com/kaisermann/svelte-preprocess/commit/3a045bd2494cb5b205fec90c4aef87817fea7a42) | ||
- fix: 🐛 template preprocessing running on the whole file [`e37da9d`](https://github.com/kaisermann/svelte-preprocess/commit/e37da9d5f8f5fde5077e02add17be039db729e32) | ||
## [v2.9.0](https://github.com/kaisermann/svelte-preprocess/compare/v2.7.1...v2.9.0) - 2019-05-15 | ||
@@ -12,0 +24,0 @@ |
{ | ||
"name": "svelte-preprocess", | ||
"version": "2.9.0", | ||
"version": "2.10.0", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -83,3 +83,3 @@ # Svelte Preprocess | ||
<style type="text/stylus"> | ||
$color = red | ||
$color= red | ||
@@ -91,2 +91,8 @@ div | ||
#### Limitations | ||
##### `typescript` | ||
Since `typescript` is not officially supported by `svelte` for its template language, `svelte-preprocess` only type checks code between the `<script></script>`. | ||
## Usage | ||
@@ -93,0 +99,0 @@ |
const stripIndent = require('strip-indent') | ||
const { version } = require('svelte/package.json') | ||
const { | ||
@@ -12,2 +13,4 @@ addLanguageAlias, | ||
const SVELTE_MAJOR_VERSION = +version[0] | ||
const ALIAS_OPTION_OVERRIDES = { | ||
@@ -31,2 +34,3 @@ sass: { | ||
// istanbul ignore else | ||
if (typeof optionsCache[alias] === 'undefined') { | ||
@@ -105,2 +109,8 @@ let opts = transformers[lang] || {} | ||
if (isFn(onBefore)) { | ||
// istanbul ignore next | ||
if (SVELTE_MAJOR_VERSION >= 3) { | ||
console.warn( | ||
'[svelte-preprocess] For svelte >= v3, instead of onBefore(), prefer to prepend a preprocess object to your array of preprocessors', | ||
) | ||
} | ||
content = await onBefore({ content, filename }) | ||
@@ -128,13 +138,15 @@ } | ||
/** Remove the <template></template> */ | ||
content = | ||
/** Transform the found template code */ | ||
let { code, map, dependencies } = await markupTransformer({ | ||
content: templateCode, | ||
attributes, | ||
filename, | ||
}) | ||
code = | ||
content.slice(0, templateMatch.index) + | ||
templateCode + | ||
code + | ||
content.slice(templateMatch.index + fullMatch.length) | ||
/** Remove extra indentation */ | ||
content = stripIndent(content) | ||
/** If language is HTML, just remove the <template></template> tags */ | ||
return markupTransformer({ content, attributes, filename }) | ||
return { code, map, dependencies } | ||
}, | ||
@@ -141,0 +153,0 @@ script: scriptTransformer, |
const ts = require('typescript') | ||
const path = require('path') | ||
const { dirname, basename, resolve } = require('path') | ||
const { existsSync } = require('fs') | ||
function createFormatDiagnosticsHost(cwd) { | ||
return { | ||
getCanonicalFileName: fileName => fileName, | ||
getCurrentDirectory: () => cwd, | ||
getNewLine: () => ts.sys.newLine, | ||
} | ||
} | ||
function formatDiagnostics(diagnostics, basePath) { | ||
if (Array.isArray(diagnostics)) { | ||
return ts.formatDiagnosticsWithColorAndContext( | ||
diagnostics, | ||
createFormatDiagnosticsHost(basePath), | ||
) | ||
} | ||
return ts.formatDiagnostic(diagnostics, createFormatDiagnosticsHost(basePath)) | ||
} | ||
function getFilenameExtension(filename) { | ||
filename = basename(filename) | ||
const lastDotIndex = filename.lastIndexOf('.') | ||
if (lastDotIndex <= 0) return '' | ||
return filename.substr(lastDotIndex + 1) | ||
} | ||
function isSvelteFile(filename) { | ||
const importExtension = getFilenameExtension(filename) | ||
return importExtension === 'svelte' || importExtension === 'html' | ||
} | ||
const IMPORTEE_PATTERN = /['"](.*?)['"]/ | ||
function isValidSvelteImportDiagnostic(filename, diagnostic) { | ||
// TS2307: 'cannot find module' | ||
if (diagnostic.code !== 2307) return false | ||
const importeeMatch = diagnostic.messageText.match(IMPORTEE_PATTERN) | ||
// istanbul ignore if | ||
if (!importeeMatch) return false | ||
let [, importeePath] = importeeMatch | ||
/** if we're not dealing with a relative path, assume the file exists */ | ||
if (importeePath[0] !== '.') return true | ||
/** if the importee is not a svelte file, do nothing */ | ||
if (!isSvelteFile(importeePath)) return false | ||
importeePath = resolve(dirname(filename), importeePath) | ||
if (existsSync(importeePath)) return true | ||
return false | ||
} | ||
const TS_TRANSFORMERS = { | ||
before: [ | ||
context => { | ||
const visit = node => { | ||
if (ts.isImportDeclaration(node)) { | ||
const importedFilename = node.moduleSpecifier.getText().slice(1, -1) | ||
// istanbul ignore else | ||
if (isSvelteFile(importedFilename)) { | ||
return ts.createImportDeclaration( | ||
node.decorators, | ||
node.modifiers, | ||
node.importClause, | ||
node.moduleSpecifier, | ||
) | ||
} | ||
} | ||
return ts.visitEachChild(node, child => visit(child), context) | ||
} | ||
return node => ts.visitNode(node, visit) | ||
}, | ||
], | ||
} | ||
function compileFileFromMemory(compilerOptions, { filename, content }) { | ||
let code = content | ||
let map | ||
const realHost = ts.createCompilerHost(compilerOptions, true) | ||
const dummyFilePath = filename | ||
const dummySourceFile = ts.createSourceFile( | ||
dummyFilePath, | ||
code, | ||
ts.ScriptTarget.Latest, | ||
) | ||
const host = { | ||
fileExists: filePath => | ||
filePath === dummyFilePath || realHost.fileExists(filePath), | ||
directoryExists: | ||
realHost.directoryExists && realHost.directoryExists.bind(realHost), | ||
getCurrentDirectory: realHost.getCurrentDirectory.bind(realHost), | ||
getDirectories: realHost.getDirectories.bind(realHost), | ||
getCanonicalFileName: fileName => realHost.getCanonicalFileName(fileName), | ||
getNewLine: realHost.getNewLine.bind(realHost), | ||
getDefaultLibFileName: realHost.getDefaultLibFileName.bind(realHost), | ||
getSourceFile: ( | ||
fileName, | ||
languageVersion, | ||
onError, | ||
shouldCreateNewSourceFile, | ||
) => | ||
fileName === dummyFilePath | ||
? dummySourceFile | ||
: realHost.getSourceFile( | ||
fileName, | ||
languageVersion, | ||
onError, | ||
shouldCreateNewSourceFile, | ||
), | ||
readFile: filePath => | ||
// istanbul ignore next | ||
filePath === dummyFilePath ? content : realHost.readFile(filePath), | ||
useCaseSensitiveFileNames: () => realHost.useCaseSensitiveFileNames(), | ||
writeFile: (fileName, data) => { | ||
if (fileName.endsWith('.map')) { | ||
map = data | ||
} else { | ||
code = data | ||
} | ||
}, | ||
} | ||
const program = ts.createProgram([dummyFilePath], compilerOptions, host) | ||
const emitResult = program.emit( | ||
undefined, | ||
undefined, | ||
undefined, | ||
undefined, | ||
TS_TRANSFORMERS, | ||
) | ||
// collect diagnostics without svelte import errors | ||
const diagnostics = [ | ||
...emitResult.diagnostics, | ||
...ts.getPreEmitDiagnostics(program), | ||
].reduce((acc, { file, ...diagnostic }) => { | ||
if (isValidSvelteImportDiagnostic(filename, diagnostic)) { | ||
return acc | ||
} | ||
acc.push({ | ||
file, | ||
...diagnostic, | ||
}) | ||
return acc | ||
}, []) | ||
return { code, map, diagnostics } | ||
} | ||
module.exports = ({ content, filename, options }) => { | ||
const fileDirectory = options.tsconfigDirectory || path.dirname(filename) | ||
const fileDirectory = options.tsconfigDirectory || dirname(filename) | ||
const tsconfigPath = | ||
options.tsconfigPath || ts.findConfigFile(fileDirectory, ts.sys.fileExists) | ||
const basePath = tsconfigPath ? path.dirname(tsconfigPath) : process.cwd() | ||
const basePath = tsconfigPath ? dirname(tsconfigPath) : process.cwd() | ||
let compilerOptionsJSON = options.compilerOptions || {} | ||
let compilerOptionsJSON = Object.assign( | ||
// default options | ||
{ | ||
moduleResolution: 'node', | ||
sourceMap: true, | ||
strict: true, | ||
}, | ||
options.compilerOptions, | ||
) | ||
if (tsconfigPath) { | ||
const { error, config } = ts.readConfigFile(tsconfigPath, ts.sys.readFile) | ||
if (error) { | ||
const err = ts.formatDiagnostic( | ||
error, | ||
createFormatDiagnosticsHost(basePath), | ||
) | ||
throw new Error(err) | ||
throw new Error(formatDiagnostics(error, basePath)) | ||
} | ||
compilerOptionsJSON = { | ||
...(config.compilerOptions || {}), | ||
...compilerOptionsJSON, | ||
} | ||
compilerOptionsJSON = Object.assign( | ||
{}, | ||
compilerOptionsJSON, | ||
config.compilerOptions, | ||
) | ||
} | ||
@@ -28,39 +190,29 @@ | ||
errors, | ||
options: compilerOptions, | ||
options: convertedCompilerOptions, | ||
} = ts.convertCompilerOptionsFromJson(compilerOptionsJSON, basePath) | ||
if (errors.length) { | ||
const err = ts.formatDiagnostics( | ||
errors, | ||
createFormatDiagnosticsHost(basePath), | ||
) | ||
throw new Error(err) | ||
throw new Error(formatDiagnostics(errors, basePath)) | ||
} | ||
const { | ||
outputText: code, | ||
sourceMapText: map, | ||
diagnostics, | ||
} = ts.transpileModule(content, { | ||
fileName: filename, | ||
compilerOptions: compilerOptions, | ||
reportDiagnostics: options.reportDiagnostics !== false, | ||
const compilerOptions = { | ||
...convertedCompilerOptions, | ||
allowNonTsExtensions: true, | ||
} | ||
const { code, map, diagnostics } = compileFileFromMemory(compilerOptions, { | ||
filename, | ||
content, | ||
}) | ||
if (diagnostics.length) { | ||
const diagnosticMessage = ts.formatDiagnostics( | ||
diagnostics, | ||
createFormatDiagnosticsHost(basePath), | ||
) | ||
console.log(diagnosticMessage) | ||
if (diagnostics.length > 0) { | ||
// could this be handled elsewhere? | ||
const formattedDiagnostics = formatDiagnostics(diagnostics, basePath) | ||
console.log(formattedDiagnostics) | ||
} | ||
return { code, map } | ||
} | ||
function createFormatDiagnosticsHost(cwd) { | ||
return { | ||
getCanonicalFileName: fileName => fileName, | ||
getCurrentDirectory: () => cwd, | ||
getNewLine: () => ts.sys.newLine, | ||
code, | ||
map, | ||
diagnostics, | ||
} | ||
} |
@@ -77,3 +77,7 @@ const { readFile } = require('fs') | ||
} catch (e) { | ||
throwError(`Error transforming '${name}'. Message:\n${e.message}`) | ||
throwError( | ||
`Error transforming '${name}'. Message:\n${e.message}\nStack:\n${ | ||
e.stack | ||
}`, | ||
) | ||
} | ||
@@ -80,0 +84,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
40518
623
284
15