Javascript #include implemented in Python

Started by
5 comments, last by Lith 9 years, 10 months ago

So I was learning and messing around with javascript and html5 canvas when I found out that javascript has no include or import.

you either have to include extra files through the html or do some funky asynchronous loading or get Jquery to do it for you.

So a few hours later I produce this:


# compile.py

# command line utility that takes a javascript file (any text file really)
# as input, goes though it and replaces #include with
# the appropriate js files. Also minimises the resulting 
# large file and saves it.

# minimising and saving not yet implemented

# usage: compile.py file.js

# options:
# -m  minimised the resulting file.
# -o specify output filename
# NOTE - none of these implemented yet

import sys
import argparse

# handle arguments
parser = argparse.ArgumentParser( description="update this later pls" )
parser.add_argument( "filename" )
parser.add_argument( "-m", "--minimise", help="minimises the resultant file", action="store_true" )
parser.add_argument( "-o", "--output", help="filename of the resultant file" )
args = parser.parse_args()

# set options
optInputfile = args.filename
optMinimise = True if args.minimise else False
optOutputfile = args.output if args.output else "COMPILED_" + optInputfile

# extracts the next filename in double or single quotes from a position
def extract_filename ( string, position ):
    curPos = position
    curString = ""
    done = False
    inName = False
    while not done:
        if not inName:
            if string[curPos] == '"' or string[curPos] == "'":
                inName = True
        else:
            if string[curPos] != '"' and string[curPos] != "'":
                curString += string[curPos]
            else:
                done = True
        curPos += 1
        if curPos-position >= 40:
            # probably a missing " or '
            print( "COMPILE ERROR: #include filename too long. You've probably missed a ' or \"" )
            break
    return curString

# replaces everything with spaces in 'string' from 'position' until 2 ' or " are found
def replace_include_line ( string, position ):
    curPos = position
    done = False
    quoteCount = 0
    curLen = 0
    while not done:
        curLen += 1
        if string[curPos] == '"' or string[curPos] == "'":
            quoteCount += 1
        if quoteCount >= 2:
            done = True
        curPos += 1
    newString = string[:position-1] + string[position+curLen:]
    return newString

# inserts string 'b' into string 'a' at position 'pos'
def string_insert ( a, b, pos ):
    return a[:pos] + b + a[pos:]

# recursive file parsing function
def parse_file ( filename ):
    file = open( filename, 'r' )
    fileStr = file.read()
    count = 0
    pos = 0
    while True:
        # find the next include
        pos = fileStr.find( "#include", pos )
        if pos == -1: break
        # read the filename
        includeFilename = extract_filename( fileStr, pos )
        # remove the #include from file
        fileStr = replace_include_line( fileStr, pos )
        # insert the included file
        fileStr = string_insert( fileStr, parse_file( includeFilename ), pos ) # woah here's where the magic happens
    return fileStr
    

print( parse_file( optInputfile ) )

It's a command line utility written in Python that parses text files for #include statements and inserts the appropriate files.

It's far from elegant and most of the extra features aren't done yet, at the moment it just prints out the resulting superfile. But the basic functionality of recursively replacing #include with the contents of a file is done.

So in any file that's parsed you can write:


#include "file.ext"

Thoughts? Am I crazy? Wasting my time? Has this been done/solved before?

Advertisement

Thoughts? Am I crazy? Wasting my time? Has this been done/solved before?

None. Yes. Yes. Yes, requirejs.
Additionally, javascript already manages "includes"; just not in the way you expect:

<head>
<script type="text/javascript" src="a.js"></script>
</head>
<body>
<script type="text/javascript" src="b.js"></script>
<script type="text/javascript" src="c.js"></script>
</body>
Here, 'b' knows of 'a', and 'c' knows of the others. If 'b' were to define 'foobar', it'd be visible to 'b' and 'c', but not 'a'.

Oh well I had fun...

EDIT: And I forgot to close the file afterwards -.-

As others stated, there's already standard-ish ways to do includes with JS (AMD, CommonJS, HTML, etc.), but if you're really after #include then you can just use

gcc -E source.js > expanded.js

Also then handles #define, #if, etc.

Most other C compilers also offer a preprocessor-only mode and there's also standalone preprocessors.

Sean Middleditch – Game Systems Engineer – Join my team!

Wouldn't replacing #includes in javascript files create a lot of duplicated code? If you have 2 javascript files that include "foo.js" you'll end up with 2 js files with that code at the top, and if you use both in an HTML file you might get into troubles.

If you still go with this approach I think you should also implement the "#ifdef" functionality and you should be sure that the only copy of the file is in the first js file you use in your html code, or pasting all te includes in one separate js file instead of the top of each file that includes it.

Wouldn't replacing #includes in javascript files create a lot of duplicated code?

Yep, you're right. Include guards are one of the features I hadn't got around to implementing yet.

I kinda knew this was a bad idea, hence me posting this in coding horrors biggrin.png

Still, I've learned some good little bits from the posts here, thanks everyone.

I've decided to finish this and use it for the project that I made it for. Just for the fun of it. Who knows, I might learn something more..

But yeah never again -.-

This topic is closed to new replies.

Advertisement