Analyze javascript file using Typescript Compiler - javascript

Refer to: https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API, I want to get type of node in AST.
It is successful for angular project because it is written using typescript and tsconfig.json exists.
When I try to analyze react app which is written using javascript
const program = ts.createProgram({
rootNames: [fileName],
options: {
strict: true,
target: ts.ScriptTarget.ES2015,
allowJs: true,
checkJs: true
}
})
const typeChecker = program.getTypeChecker();
... ...
I get: typechecker.getTypeAtLocation(node).getSymbol() is undefined.
I assume options of ts.createProgram is wrong.

the option: moduleResolution: ts.ModuleResolutionKind.NodeJs is key.
const program = ts.createProgram({
rootNames: [file1],
options: {
strict: true,
target: ts.ScriptTarget.ES2015,
allowJs: true,
checkJs: true,
moduleResolution: ts.ModuleResolutionKind.NodeJs
}
})
The above works for React JS.

Related

How to not include mocha (TDD) functions like "describe" and "it" in my src folder and only contain them in test folder? [TS]

Mocha.js functions like describe() and it() are available everywhere in my project, but I only want them to be only accessible and callable in my "test" folder. Is there any way to do that?
P.S. I'm using typescript if that makes a difference.
I think your question is really vague. Still I am going to try to answer assming that you use eslint...
In your .eslintrc.js (or eslint config file), you may have:
module.exports = {
env: {
browser: true,
es6: true,
node: true,
mocha: true
}
(...)
Where you should have:
module.exports = {
env: {
browser: false,
es6: true,
node: true
},
(...)
overrides: [
{
files: 'test/**/*.spec.js',
env: {
mocha: true,
},
},
],

Jest throwing ReferenceError to default exports

Jest is unable to find functions which are export default but IS able to find export const. I can go through and redefine how all of my functions are exported/imported, but I feel this is likely just a config issue but have been unable to find any solution on the docs or github issues to solve it.
Does anyone know of some jest config which can be used to resolve this?
GOOD
file:
export const MyFunction = () => {..
spec:
import { MyFunction } from "src/MyFunction";
=> ● Pass
BAD
file:
export default MyFunction = () => {..
spec:
import MyFunction from "src/MyFunction";
=> ● Test suite failed to run
ReferenceError: MyFunction is not defined
My jest.config.js:
/*
* For a detailed explanation regarding each configuration property, visit:
* https://jestjs.io/docs/en/configuration.html
*/
module.exports = {
// All imported modules in your tests should be mocked automatically
// automock: false,
// Automatically restore mock state between every test
restoreMocks: true,
// Make calling deprecated APIs throw helpful error messages
errorOnDeprecated: true,
// An array of directory names to be searched recursively up from the requiring module's location
moduleDirectories: ["node_modules", "src", "test/unit"],
// The test environment that will be used for testing
testEnvironment: "node",
// The glob patterns Jest uses to detect test files
testMatch: ["**/test/**/**/*.spec.(js|jsx|ts|tsx)"],
transformIgnorePatterns: [
"node_modules/(?!(jest-)?react-native|react-clone-referenced-element|#react-native-community|expo(nent)?|#expo(nent)?/.*|react-navigation|#react-navigation/.*|#unimodules/.*|unimodules|sentry-expo|native-base|#sentry/.*)",
],
transform: {
"\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js",
},
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
testPathIgnorePatterns: ["/node_modules/"],
reporters: ["default", "jest-junit"],
collectCoverage: true,
coverageReporters: ["lcov", "text-summary"],
coveragePathIgnorePatterns: [
"/node_modules/",
"src/img/",
"src/styles/",
"test/factories/",
"test/fixtures/",
],
// Whether to use watchman for file crawling
watchman: true,
setupFilesAfterEnv: ["#testing-library/jest-native/extend-expect"],
preset: "jest-expo",
globals: {
__DEV__: true,
THEME: true,
SEGMENT_KEY_STORE_INFO: true,
INITIAL_STATE: true,
EMPTY_MESSAGE: true,
},
};
export default MyFunction = () => {..
Change this to
export default const MyFunction = () => {..
Ok guys stupid one here, but the solution is to change the default export to:
MyFunction.js:
export default () => {..
Ie drop the name in the export default function declaration. Hope this helps someone having this issue.

Rollup is not generating typescript sourcemap

I am using rollup with svelte + typescript + scss. My problem is that I am not able to generate source maps.
Following is my rollup config file:
import svelte from 'rollup-plugin-svelte'
import resolve from '#rollup/plugin-node-resolve'
import commonjs from '#rollup/plugin-commonjs'
import livereload from 'rollup-plugin-livereload'
import { terser } from 'rollup-plugin-terser'
import typescript from '#rollup/plugin-typescript'
import alias from '#rollup/plugin-alias'
const production = !process.env.ROLLUP_WATCH
const path = require('path').resolve(__dirname, 'src')
const svelteOptions = require('./svelte.config')
function serve() {
let server
function toExit() {
if (server) server.kill(0)
}
return {
writeBundle() {
if (server) return
server = require('child_process').spawn(
'yarn',
['run', 'start', '--', '--dev'],
{
stdio: ['ignore', 'inherit', 'inherit'],
shell: true,
}
)
process.on('SIGTERM', toExit)
process.on('exit', toExit)
},
}
}
export default {
input: 'src/main.ts',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js',
},
plugins: [
alias({
entries: [
{ find: '#app', replacement: `${path}` },
{ find: '#components', replacement: `${path}/components` },
{ find: '#includes', replacement: `${path}/includes` },
{ find: '#styles', replacement: `${path}/styles` },
{ find: '#pages', replacement: `${path}/pages` },
],
}),
svelte(svelteOptions),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte'],
}),
commonjs(),
typescript({ sourceMap: !production }),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser(),
],
watch: {
clearScreen: false,
},
}
I am not sure what exactly am I doing wrong. Here is the link to code I am using.
Any help will be deeply appreciated!
This is what worked for me: you need to set sourceMap: false in the typescript rollup plugin options.
export default {
input: 'src/main.ts',
output: {
sourcemap: true,
format: 'iife',
...
},
plugins: [
...
svelte(...),
typescript({ sourceMap: false }),
...
]
}
It turns out rollup's sourcemap collapser conflicts with the typescript's plugin sourcemap generator. That's why it works on prod builds but not in dev builds (because originally it is sourceMap: !production). Just let rollup do the heavy lifting.
As also mentioned by others, it seems like the combination of TypeScript and Rollup leads to the problem. Disabling the source map in TypeScript only fixes the problem of mapping Svelte to TypeScript. However you only receive a source map showing source in the compiled JavaScript, not in the original TypeScript. I finally found a solution, that worked for me: Just add the Option inlineSources: true to the TypeScript options:
typescript({ sourceMap: !production, inlineSources: !production }),
This circumvents the problem by simply not creating a duplicate SourceMap, but by copying the source code from TypeScript into the SourceMap.
For anyone using terser, not svelte, this solved the same problem for me:
import sourcemaps from 'rollup-plugin-sourcemaps';
import { terser } from 'rollup-plugin-terser';
import typescript from '#rollup/plugin-typescript';
export default [
{
input: 'dist/index.js',
output: [
{
file: 'dist/cjs/index.js',
format: 'cjs'
},
{
file: 'dist/fesm2015/index.js',
format: 'es'
}
],
plugins: [
sourcemaps(),
terser(),
typescript({ sourceMap: true, inlineSources: true })
]
}
];
Apparently rollup-plugin-sourcemaps is needed to do the magic necessary to utilize the map files generated by the TypeScript compiler and feed them to terser.
For me, I am able to map, by making sourcemap: "inline"
In the /build/index.esm.js file will have mapping inside.
export default {
input: "src/index.ts",
output: [
{
file: 'build/index.esm.js',
format: 'es',
sourcemap: "inline"
},
],
plugins: [
typescript({ sourceMap: false, inlineSources: true }),
]
}
I was having a similar issue with Karma, rollup, and typescript. I fixed it by adding "sourceRoot":"/base/" to my tsconfig.json file.
Before: map file entries pointed to /src/.
After: map file entries pointed to /base/src/ and everything worked.
// tsconfig.rollup.json
"compilerOptions": {
"module": "ES2022",
"esModuleInterop": true,
"target": "ES2022",
"moduleResolution": "classic",
"sourceMap": true,
"sourceRoot": "/base/"
...
}
// rollup.config.js
import typescript from '#rollup/plugin-typescript';
export default [
{
input: './src/test/test_context.spec.ts',
output: {
file: './dist/test/test_context.spec.js',
format: 'es',
sourcemap: 'inline'
},
plugins: [
typescript({
tsconfig: './tsconfig.rollup.json'
})
]
}
];

How to properly import and use the MSAL (Microsoft Authentication Library for js) into a typescript react single page application?

Problem
I can't seem to get the MSAL library to import properly into my typescript code. I'm using the MSAL for JS library (which is supposed to have typings) in a simple typescript/react project scaffolded using the create-react-app with react-typescript scripts. I'm new to typescript and not sure if I'm missing something obvious or if there is a problem with the MSAL package when using it with typescript projects.
Details:
I added the MSAL package from NPM using npm install --save msal.
I attempted to import the MSAL into my .ts using different forms of import {Msal} from 'msal';
This results in a typescript error Could not find a declaration file for module 'msal'. '<path>/node_modules/msal/out/msal.js' implicitly has an 'any' type.
Thinking that was odd, I looked at the the node_module/msal/out folder and saw a 'msal.d.ts' file, which is what I would expect.
When I look at the contents of the msal.d.ts file, I don't see any exports, which I would normally expect to see.
I tried install the declaration from #types using npm install --save-dev #types/msal, but it doesn't exist.
I also tried importing it into my file using let Msal = require('Msal');, but get an error that the Msal.UserAgentApplication isn't a constructor.
I didn't have much luck trying to use the /// reference directive and adding a script tag to the main index.html. This also doesn't feel like the right way to solve the problem.
ExampleMsal.ts
import { observable, action, computed } from 'mobx';
import * as Msal from 'msal'; // <-- This line gives the error
class ExampleMsal{
#observable
private _isLoggedIn: boolean;
constructor() {
this._isLoggedIn = false;
}
#computed
get isLoggedIn(): boolean {
return this._isLoggedIn;
}
#action
signIn() {
let userAgentApplication = new Msal.UserAgentApplication('<client-id>', null,
function (errorDes: string, token: string, error: string, tokenType: string) {
// this callback is called after loginRedirect OR acquireTokenRedirect
// (not used for loginPopup/aquireTokenPopup)
}
);
userAgentApplication.loginPopup(['user.read']).then(function(token: string) {
let user = userAgentApplication.getUser();
if (user) {
// signin successful
alert('success');
} else {
// signin failure
alert('fail');
}
}, function (error: string) {
// handle error
alert('Error' + error);
});
this._isLoggedIn = true;
}
#action
signOut() {
this._isLoggedIn = false;
}
}
export default ExampleMsal;
tsconfig.json
{
"compilerOptions": {
"outDir": "build/dist",
"module": "commonjs",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"experimentalDecorators": true
},
"exclude": [
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts"
],
"types": [
"typePatches"
]
}
It looks like the latest version of MSAL.js does have a CommonJS export. You can now just do the following in TypeScript (tested with version 2.3.3 of TypeScript and 0.1.3 of MSAL.js):
import * as Msal from 'msal';
Now in your .ts (or in my case .tsx file) you can, for instance, setup a click event handler and create a UserAgentApplication object:
// In you class somewhere
private userAgentApplication: any = undefined;
// The login button click handler
handleLoginClick = (event: any): void => {
if (!this.userAgentApplication) {
this.userAgentApplication = new Msal.UserAgentApplication(
'clientID string', 'authority string or empty', this.authCallback, { cacheLocation: 'localStorage'});
}
// Other login stuff...
}
// In React render()
public render() {
return (
<Button
bsStyle="warning"
type="button"
onClick={(e) => this.handleLoginClick(e)}
>
Log in
</Button>
);
}
As you have correctly mentioned - in the msal.d.ts there are no exports - its not a module, and therefore you should not try importing.
Instead you can use it like this:
/// <reference path="./node_modules/msal/out/msal.d.ts" />
const userAgentApplication = new Msal.UserAgentApplication("your_client_id", null, (errorDes, token, error, tokenType) =>
{
});
Note that even in readme they specify only one way of using their library - by including script tag, not by importing module. And further looking into their source code shows they are not using modules as well.
I had the same issue and couldn't wait for the author to fix it, so forked and modified the original code. Just as a temporary fix you can use my version msalx instead of msal.
npm install msalx
You can find the source code and an example usage in react at: https://github.com/malekpour/microsoft-authentication-library-for-js#example
If you install the exports-loader (npm install exports-loader --save-dev) you can avoid the script tag and add the following to your directives:
var Msal = require("exports-loader?Msal!../../../node_modules/msal/out/msal.js");

Systemjs-Builder - Cannot configure properly - Bundling Typescript into a package

I want to build a quick nodejs script to package a Typescript app as SystemJS modules, a lot like what Angular2 bundles look like.
I tried different configurations but I can't seem to put my finger on it, and haven't found clear enough documentation as of yet.
Note that for this "test", I am not using Gulp or Jspm at all, just systemjs-builder for the time being (and don't plan on using jspm at all either)
Here's what my "project" looks like:
---- Project's Root
-------- index.ts // export * from './modules/index' and eventually more
-------- modules
------------ index.ts // export * from './menu/index'
------------ menu
---------------- menu.component.ts // export class
---------------- menu.service.ts // export class
I want to package this under a single file, where I will have multiple SystemRegister modules that can be consumed in an app thereafter
I tried the following without success:
var Builder = require('systemjs-builder');
// optional constructor options
// sets the baseURL and loads the configuration file
var builder = new Builder('./modules');
builder.bundle('./modules/index.ts', {
/* SystemJS Configuration Here */
baseURL: './modules',
transpiler: 'typescript',
typescriptOptions: {
"module": "system",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
defaultExtension: 'ts',
packages: {
'modules': {
defaultExtension: 'ts'
}
}
}, 'infrastructure.js')
.then(function() {
console.log('Build complete');
})
.catch(function(err) {
console.error(err);
})
First of all, the defaultExtension options doesn't seem to work at all
So when I do import {something} from 'filePath'; (without extension), it tries to load filePath, instead of filePath.ts;
Second, if I try adding the .ts extension in my imports (which I don't want to do), it complains that the code is invalid (unexpected token #, unexpected token menuItem and so forth)
Anyone have a good example or some explanations on how this is supposed to work?
Thank you
here you have an example: angular typescript skeleton
build task looks like this:
const path = require('path');
const Builder = require('jspm').Builder;
const builder = new Builder();
const packageJson = require(path.join(config.projectDir, 'package.json'));
return beginBuild()
.then(buildSFX)
.catch((err) => console.log('Build Failed', err));
function beginBuild() {
builder.reset();
return builder.loadConfig(path.join(config.projectDir, packageJson.jspm.configFile))
}
function buildSFX() {
const appName = packageJson.name;
const distFileName = `${appName}.min.js`;
const outFile = path.join(config.distDir, distFileName);
const moduleName = 'app';
const buildConfig = {
format: 'global',
minify: true,
sourceMaps: true
};
return builder.buildStatic(moduleName, outFile, buildConfig);
}
and jspm conf looks like this:
System.config({
defaultJSExtensions: true,
transpiler: "typescript",
typescriptOptions: {
"tsconfig": "src/tsconfig.json"
},
paths: {
"github:*": "vendor/jspm_packages/github/*",
"npm:*": "vendor/jspm_packages/npm/*",
"app": "src/index"
}
/// ...
}
Why do you want to bundle typescript? Bundling is a method used for optimizing the delivery of source code to the browser. The browser doesn't know typescript, it only knows javascript (unless you do on the fly transpiling).

Categories